Write a C / C++ Polyglot

27

2

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.

Mewy

Posted 2014-11-14T22:37:28.010

Reputation: 389

5I'm sure this is a dupe of something... – Beta Decay – 2014-11-14T23:39:30.120

@BetaDecay Is it? I tried searching for something similar and I couldn't find anything. – Mewy – 2014-11-15T00:03:02.857

Can you please explain how your program works differently (if it doesn't spoil the challenge)? – A.L – 2014-11-15T02:48:57.840

@A.L I edited in an explanation to my post. – Mewy – 2014-11-15T03:11:11.347

All the ones from http://stackoverflow.com/questions/2038200/write-a-program-that-will-print-c-if-compiled-as-an-ansi-c-program-and-c/ could be used here - with a little obfuscation.

– Jerry Jeremiah – 2014-11-15T03:51:13.747

Answers

18

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!

es1024

Posted 2014-11-14T22:37:28.010

Reputation: 8 953

1This. I like this. – FUZxxl – 2015-02-28T18:38:38.727

9

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

Qwertiy

Posted 2014-11-14T22:37:28.010

Reputation: 2 697

bool is not part of C89 – malat – 2014-11-20T11:13:27.153

8@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. – Qwertiy – 2014-11-20T19:44:04.870

5

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?

Jerry Jeremiah

Posted 2014-11-14T22:37:28.010

Reputation: 1 217

Although others did the same thing, you masked it pretty well. – kirbyfan64sos – 2015-04-22T15:54:40.500

5

#include <stdio.h>

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

Display_name

Posted 2014-11-14T22:37:28.010

Reputation: 330

4

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.

Felix Bytow

Posted 2014-11-14T22:37:28.010

Reputation: 311

1Doesn't work with C11 as C11 has removed the implicit int rule. – FUZxxl – 2015-02-28T18:39:45.380

@FUZxxl Thanks, I adjusted my post. – Felix Bytow – 2015-03-01T12:41:38.090

1

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.

kirbyfan64sos

Posted 2014-11-14T22:37:28.010

Reputation: 8 730