/** c-or-cpp.c -- by James D. Lin (last updated: 2012-05-17) * * Prints "C" if compiled with a C compiler, "C++" if compiled with a * C++ one, all without using preprocessor tricks. */ #include #include #ifndef STRICT #define STRICT 1 #endif int isC = 0; void Foo() { isC = 1; } int main(void) { /* Method 1A: * Abuse C++ automatic typedefs and ambiguity between sizeof (variable) * and sizeof (type). Suggested by Walter Luh. * * Note that the struct needs to be declared in an inner scope so that * it takes precedence over the variable name in C++. */ { char x; { struct x { char dummy[2]; }; printf("1A: %s\n", sizeof (x) == 1 ? "C" : "C++"); } (void) x; /* Silence compiler warnings about unused variables. */ } /* Method 1B: * Similar to method 1A but with only types and no variables. */ { typedef char t; { struct t { char dummy[2]; }; printf("1B: %s\n", sizeof (t) == 1 ? "C" : "C++"); } } /* Method 2: * Abuse C++ struct/class equivalence, automatic typedefs, and * automatically-generated default constructors. * * In C++, Foo() constructs a Foo struct. In C, Foo() invokes the * global Foo function. * * Again, the struct needs to be declared in a different scope from * the function declaration. */ { struct Foo { int dummy; }; Foo(); printf("2: %s\n", isC ? "C" : "C++"); } /* Method 3: * Abuse nested struct declarations in C. The typenames of nested C * structs live in the same scope as the outer struct (C does not have * a :: operator). * * This requires another inner scope so that the struct name collision * doesn't generate a redefinition error in C. * * Inspired by: * */ { typedef struct inner { int dummy; } t; { struct outer { struct inner { t dummy[2]; } dummy; }; printf("3: %s\n", sizeof (struct inner) == sizeof (t) ? "C++" : "C"); } } /* Method 4A: * Abuse // comments and unary +. * * In C++, // will be parsed as the start of a comment, causing the * conditional expression to be parsed as 0 + 1 => 1. * * In C (using a strict ANSI C89 compiler), // is not recognized * as a comment, causing the conditional expression to be parsed as * 0 / +1 => 0. * * Won't work with C99. */ printf("4A: %s\n", 0 //* */ +1 ? "C++ (are you using a strict ANSI C89 compiler?)" : "C"); /* Method 4B: * Simplified variant of method 4A that abuses integer division instead * of unary +. Suggested by Billy Martin. * * Won't work with C99. */ printf("4B: %s\n", 1 //* */ 2 ? "C++ (are you using a strict ANSI C89 compiler?)" : "C"); /* Method 5: * C treats character literals as ints, but C++ treats them as actual * chars. Suggested by Mark West. * * Note that this method is not entirely portable; although C requires * that an int be capable of storing 16-bit signed values, a * hypothetical implementation could define a byte (and consequently * char) to have 16 bits or more. * * Also see: */ printf("5: %s\n", sizeof 'a' == 1 ? "C++" : "C"); /* Method 6: * Abuse differences in when lvalue=>rvalue conversions are performed. * This is derived from an example in the ISO C++ standard. * * In C, the comma operator in (..., array) converts array from an * lvalue to an rvalue, so sizeof returns the size of the pointer that * the array decays into. * * In C++, the comma operator can yield an lvalue, so sizeof returns the * size of the undecayed array. * * NB: The (void) cast is just to quiesce a compiler warning about the * LHS having no effect. * * This doesn't seem to work with MSVC, possibly due to a compiler bug. */ { void* array[2]; printf("6: %s\n", (sizeof (((void) 0), array) / sizeof (void*) == 1) ? "C" : "C++"); } /* Method 7: * C's grammar parses * * p ? x : y = z * * as * * (p ? x : y) = z * * whereas C++'s grammar parses it as: * * p ? x : (y = z) * * Note that this is despite ?: having a higher precedence than * = in both languages. * * Also note that this isn't strictly legal in C since ?: expressions * are not supposed to yield lvalues, but some compilers are lax. * (This is rejected by gcc 3 with -ansi -pedantic and by gcc 4.) */ #if !STRICT { int isCPP = 1; printf("7: %s\n", (1 ? isCPP : isCPP = 0) ? "C++" : "C"); } #endif return EXIT_SUCCESS; }