Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can code that is valid in both C and C++ produce different behavior when compiled in each language?

Tags:

c++

c

C and C++ have many differences, and not all valid C code is valid C++ code.
(By "valid" I mean standard code with defined behavior, i.e. not implementation-specific/undefined/etc.)

Is there any scenario in which a piece of code valid in both C and C++ would produce different behavior when compiled with a standard compiler in each language?

To make it a reasonable/useful comparison (I'm trying to learn something practically useful, not to try to find obvious loopholes in the question), let's assume:

  • Nothing preprocessor-related (which means no hacks with #ifdef __cplusplus, pragmas, etc.)
  • Anything implementation-defined is the same in both languages (e.g. numeric limits, etc.)
  • We're comparing reasonably recent versions of each standard (e.g. say, C++98 and C90 or later)
    If the versions matter, then please mention which versions of each produce different behavior.
like image 633
user541686 Avatar asked Oct 14 '12 23:10

user541686


14 Answers

Here is an example that takes advantage of the difference between function calls and object declarations in C and C++, as well as the fact that C90 allows the calling of undeclared functions:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

int f() {
    return printf("hello");
}

In C++ this will print nothing because a temporary f is created and destroyed, but in C90 it will print hello because functions can be called without having been declared.

In case you were wondering about the name f being used twice, the C and C++ standards explicitly allow this, and to make an object you have to say struct f to disambiguate if you want the structure, or leave off struct if you want the function.

like image 194
Seth Carnegie Avatar answered Sep 28 '22 04:09

Seth Carnegie


For C++ vs. C90, there's at least one way to get different behavior that's not implementation defined. C90 doesn't have single-line comments. With a little care, we can use that to create an expression with entirely different results in C90 and in C++.

int a = 10 //* comment */ 2 
        + 3;

In C++, everything from the // to the end of the line is a comment, so this works out as:

int a = 10 + 3;

Since C90 doesn't have single-line comments, only the /* comment */ is a comment. The first / and the 2 are both parts of the initialization, so it comes out to:

int a = 10 / 2 + 3;

So, a correct C++ compiler will give 13, but a strictly correct C90 compiler 8. Of course, I just picked arbitrary numbers here -- you can use other numbers as you see fit.

like image 20
Jerry Coffin Avatar answered Sep 28 '22 04:09

Jerry Coffin


The following, valid in C and C++, is going to (most likely) result in different values in i in C and C++:

int i = sizeof('a');

See Size of character ('a') in C/C++ for an explanation of the difference.

Another one from this article:

#include <stdio.h>

int  sz = 80;

int main(void)
{
    struct sz { char c; };

    int val = sizeof(sz);      // sizeof(int) in C,
                               // sizeof(struct sz) in C++
    printf("%d\n", val);
    return 0;
}
like image 20
Alexey Frunze Avatar answered Sep 28 '22 02:09

Alexey Frunze


C90 vs. C++11 (int vs. double):

#include <stdio.h>

int main()
{
  auto j = 1.5;
  printf("%d", (int)sizeof(j));
  return 0;
}

In C auto means local variable. In C90 it's ok to omit variable or function type. It defaults to int. In C++11 auto means something completely different, it tells the compiler to infer the type of the variable from the value used to initialize it.

like image 26
detunized Avatar answered Sep 28 '22 02:09

detunized


Another example that I haven't seen mentioned yet, this one highlighting a preprocessor difference:

#include <stdio.h>
int main()
{
#if true
    printf("true!\n");
#else
    printf("false!\n");
#endif
    return 0;
}

This prints "false" in C and "true" in C++ - In C, any undefined macro evaluates to 0. In C++, there's 1 exception: "true" evaluates to 1.

like image 22
godlygeek Avatar answered Sep 28 '22 02:09

godlygeek


Per C++11 standard:

a. The comma operator performs lvalue-to-rvalue conversion in C but not C++:

   char arr[100];
   int s = sizeof(0, arr);       // The comma operator is used.

In C++ the value of this expression will be 100 and in C this will be sizeof(char*).

b. In C++ the type of enumerator is its enum. In C the type of enumerator is int.

   enum E { a, b, c };
   sizeof(a) == sizeof(int);     // In C
   sizeof(a) == sizeof(E);       // In C++

This means that sizeof(int) may not be equal to sizeof(E).

c. In C++ a function declared with empty params list takes no arguments. In C empty params list mean that the number and type of function params is unknown.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C
like image 37
Kirill Kobelev Avatar answered Sep 28 '22 03:09

Kirill Kobelev


This program prints 1 in C++ and 0 in C:

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

int main(void)
{
    int d = (int)(abs(0.6) + 0.5);
    printf("%d", d);
    return 0;
}

This happens because there is double abs(double) overload in C++, so abs(0.6) returns 0.6 while in C it returns 0 because of implicit double-to-int conversion before invoking int abs(int). In C, you have to use fabs to work with double.

like image 45
Pavel Chikulaev Avatar answered Sep 28 '22 02:09

Pavel Chikulaev


#include <stdio.h>

int main(void)
{
    printf("%d\n", (int)sizeof('a'));
    return 0;
}

In C, this prints whatever the value of sizeof(int) is on the current system, which is typically 4 in most systems commonly in use today.

In C++, this must print 1.

like image 26
Adam Rosenfield Avatar answered Sep 28 '22 02:09

Adam Rosenfield


Another sizeof trap: boolean expressions.

#include <stdio.h>
int main() {
    printf("%d\n", (int)sizeof !0);
}

It equals to sizeof(int) in C, because the expression is of type int, but is typically 1 in C++ (though it's not required to be). In practice they are almost always different.

like image 28
Alex B Avatar answered Sep 28 '22 03:09

Alex B


An old chestnut that depends on the C compiler, not recognizing C++ end-of-line comments...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...
like image 22
dmckee --- ex-moderator kitten Avatar answered Sep 28 '22 04:09

dmckee --- ex-moderator kitten


The C++ Programming Language (3rd Edition) gives three examples:

  1. sizeof('a'), as @Adam Rosenfield mentioned;

  2. // comments being used to create hidden code:

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
    
  3. Structures etc. hiding stuff in out scopes, as in your example.

like image 42
derobert Avatar answered Sep 28 '22 04:09

derobert


Another one listed by the C++ Standard:

#include <stdio.h>

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}
like image 25
Johannes Schaub - litb Avatar answered Sep 28 '22 04:09

Johannes Schaub - litb


Inline functions in C default to external scope where as those in C++ do not.

Compiling the following two files together would print the "I am inline" in case of GNU C but nothing for C++.

File 1

#include <stdio.h>

struct fun{};

int main()
{
    fun();  // In C, this calls the inline function from file 2 where as in C++
            // this would create a variable of struct fun
    return 0;
}

File 2

#include <stdio.h>
inline void fun(void)
{
    printf("I am inline\n");
} 

Also, C++ implicitly treats any const global as static unless it is explicitly declared extern, unlike C in which extern is the default.

like image 31
fkl Avatar answered Sep 28 '22 04:09

fkl


#include <stdio.h>

struct A {
    double a[32];
};

int main() {
    struct B {
        struct A {
            short a, b;
        } a;
    };
    printf("%d\n", sizeof(struct A));
    return 0;
}

This program prints 128 (32 * sizeof(double)) when compiled using a C++ compiler and 4 when compiled using a C compiler.

This is because C does not have the notion of scope resolution. In C structures contained in other structures get put into the scope of the outer structure.

like image 17
wefwefa3 Avatar answered Sep 28 '22 02:09

wefwefa3