27
\$\begingroup\$

This challenge's concept is pretty simple. All you have to do is write a program that will compile as both valid C and valid C++! Well, there are some catches. The program must behave differently when compiled in each language. The program must have different output for each language in order to be considered "behaving differently".

Rules

  • The program must be both valid C and C++
  • The program must have different outputs based on the language it was compiled in.
  • #ifdef __cplusplus or other "easy" preprocessor tricks are discouraged! (Other preprocessor operations are perfectly fine, though.)
  • Try not to make it look completely obvious that the program does something different.

This is a , so whoever has the most interesting and surprising solution wins. Have fun!

Example:

I created my own program to see if this was even possible to do with out #ifdef tricks:

#include <stdio.h>
#include <string.h>

char *m="C++ rules!";

int t[11]={0,0,0,0,1,-1,-3,9,-8,82,0};

char tr(char c,int i)
{
    return c+((sizeof('!')+1)&1)*t[i];
}

int main()
{
    int i = 0;
    for(;i<strlen(m);i++)
    {
        printf("%c",tr(m[i],i));
    }
    printf("\n");
    return 0;
}

This program outputs C++ rules! when compiled in C++ and C++ stinks when compiled in C.

Explanation:

What causes the difference between languages is the tr() function. It takes advantage of one of the differences between C and C++, specifically, how char literals are treated. In C, they are treated as integers, so sizeof('!') returns 4, as opposed to 1 in C++. The ((...+1)&1) part is just part of a simple bitwise operation that will return 1 if sizeof('!') returns 4, and 0 if it returns 1. That resulting number is multiplied by the ints in array t and then that product is finally added to the specific character being transformed. In C++ the product will always be zero, so the string C++ rules! remains unchanged. In C, the product will always be the value in t, and so the string changes to C++ stinks.

\$\endgroup\$
  • 5
    \$\begingroup\$ I'm sure this is a dupe of something... \$\endgroup\$ – Beta Decay Nov 14 '14 at 23:39
  • \$\begingroup\$ @BetaDecay Is it? I tried searching for something similar and I couldn't find anything. \$\endgroup\$ – Mewy Nov 15 '14 at 0:03
  • \$\begingroup\$ Can you please explain how your program works differently (if it doesn't spoil the challenge)? \$\endgroup\$ – A.L Nov 15 '14 at 2:48
  • \$\begingroup\$ @A.L I edited in an explanation to my post. \$\endgroup\$ – Mewy Nov 15 '14 at 3:11
  • \$\begingroup\$ All the ones from stackoverflow.com/questions/2038200/… could be used here - with a little obfuscation. \$\endgroup\$ – Jerry Jeremiah Nov 15 '14 at 3:51
18
\$\begingroup\$

Is the cake a lie?

As there has been much debate over whether the cake is or is not a lie, I wrote this program to answer this contentious question.

#include <stdio.h>

// checks if two things are equal
#define EQUALS(a,b) (sizeof(a)==sizeof(b)) 

struct Cake{int Pie;}; // the cake is a pie!
typedef struct Cake Lie;
main(){
    struct CakeBox{
        struct Cake{ // the cake contains lies!
            Lie Lies[2];
        };
    };
    typedef struct Cake Cake;

    printf("The cake is ");
    if(EQUALS(Cake, Lie)){
        printf("a LIE!\n");
    }else{
        printf("..not a lie?\n");
    }
    return 0;
}

What will the outcome be?

C:

The cake is ..not a lie?

C++:

The cake is a LIE!

\$\endgroup\$
  • 1
    \$\begingroup\$ This. I like this. \$\endgroup\$ – FUZxxl Feb 28 '15 at 18:38
9
\$\begingroup\$

Just some bools

#include <stdio.h>

int test(bool)
  {
  return sizeof(bool) == sizeof(int);
  }

int main(void)
  {
  puts(test(0) ? "C" : "C++");
  return 0;
  }

http://codepad.org/dPFou20W
http://codepad.org/Ko6K2JBH

\$\endgroup\$
  • \$\begingroup\$ bool is not part of C89 \$\endgroup\$ – malat Nov 20 '14 at 11:13
  • 8
    \$\begingroup\$ @malat Yep, and exactly this fact is used in this solution. For c++ the function is int test(bool /*unnamed boolean argument*/); and for C it uses default int declaration wich means int test(int bool); so 'bool' is a name of integer variable. \$\endgroup\$ – Qwertiy Nov 20 '14 at 19:44
5
\$\begingroup\$

I could have done this with a 3 line program but then it would be obvious why it produces different results for C and C++. So instead I started writing a bigger program with some stegonography which gets different results in C and C++...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct product
{
    int quantity;
    char name[20];
    char desc[80];
}; 

struct _customer
{
    char name[80];
    struct product *products;
} customer;

int main(int argc, char *argv[])
{

struct shipment
{
    char tracking_number[40];
    int quantity;
    struct product { int model; int serial; } sku;
};

struct _supplier
{
    char name[80];
    struct shipment *shipments;
} supplier;

/* now read the command line and allocate all the space we need */

if(argc<5)
{
    printf("Usage: %s <supplier name> <# of shipments> <customer name> <# of products> ",argv[0]);
    exit(1);
}

strcpy(supplier.name,argv[1]);
int shipments_size = atoi(argv[2])*sizeof(struct shipment);
printf("Allocating %d bytes for %s shipments\n", shipments_size,supplier.name);
supplier.shipments=(struct shipment *)malloc(shipments_size);

strcpy(customer.name,argv[3]);
int products_size = atoi(argv[4])*sizeof(struct product);
printf("Allocating %d bytes for %s products\n", products_size,customer.name);

/* ... TODO ... finish the rest of this program later */

free(customer.products);
free(supplier.shipments);

return 0;
}

You need to specify a command line. When I run it on my copy of gcc I get this output:

>g++ x.cpp

>a.exe "Bob Supplier" 1 "Jane Customer" 1
Allocating 52 bytes for Bob Supplier shipments
Allocating 104 bytes for Jane Customer products

>gcc x.c

>a.exe "Bob Supplier" 1 "Jane Customer" 1
Allocating 52 bytes for Bob Supplier shipments
Allocating 8 bytes for Jane Customer products

How can things go so horribly wrong?

\$\endgroup\$
  • \$\begingroup\$ Although others did the same thing, you masked it pretty well. \$\endgroup\$ – kirbyfan64sos Apr 22 '15 at 15:54
5
\$\begingroup\$
#include <stdio.h>

int c[1]; 
int main() { 
   struct c { int cpp[2]; }; 
   printf("%d\n", (int)sizeof(c)/4);
}
\$\endgroup\$
4
\$\begingroup\$

This one works with C++11 and newer and any C so far (before C11).

#include <stdio.h>

int main()
{
    auto a = 'a';
    printf(sizeof(a) == sizeof(int) ? "C\n" : "C++\n");
    return 0;
}

See here: C++: http://ideone.com/9Gkg75 and C: http://ideone.com/eECSmr

It exploits the fact that in C++11 the auto keyword got a new meaning. So while a in C is of type int stored in an AUTOmatic location it is of type char in C++11.

EDIT: As FUZxxl said the implicit int was removed in C11.

\$\endgroup\$
  • 1
    \$\begingroup\$ Doesn't work with C11 as C11 has removed the implicit int rule. \$\endgroup\$ – FUZxxl Feb 28 '15 at 18:39
  • \$\begingroup\$ @FUZxxl Thanks, I adjusted my post. \$\endgroup\$ – Felix Bytow Mar 1 '15 at 12:41
1
\$\begingroup\$

Self-describing program

This will print "This program is written in C!" if compiled using a C compiler; otherwise, it'll print "This program is written in C++!". It needs a C99 compiler.

#include <stdbool.h>
#include <stdio.h>
char str[] = "This program is written in C++ ";
#define S (sizeof(str)-sizeof(true)-sizeof(true)%4)
int main(){for(int i=S;i<=S+1;++i)str[i]=i==S?'!':'\0';puts(str);return 0;}

Most other posts take advantage of the difference of the size of a char in C vs C++; this one uses the fact that, in C99, true is defined to be a number. This inserts the exclamation point and null terminator based on the size of true.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.