Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference in linkage between C and C++?

I have read the existing questions on external/internal linkage over here on SO. My question is different - what happens if I have multiple definitions of the same variable with external linkage in different translation units under C and C++?

For example:

/*file1.c*/

typedef struct foo {
    int a;
    int b;
    int c;
} foo;

foo xyz;


/*file2.c*/

typedef struct abc {
    double x;
} foo;

foo xyz;

Using Dev-C++ and as a C program, the above program compiles and links perfectly; whereas it gives a multiple redefinition error if the same is compiled as a C++ program. Why should it work under C and what's the difference with C++? Is this behavior undefined and compiler-dependent? How "bad" is this code and what should I do if I want to refactor it (i've come across a lot of old code written like this)?

like image 249
KC. Avatar asked Jan 08 '10 08:01

KC.


3 Answers

Both C and C++ have a "one definition rule" which is that each object may only be defined once in any program. Violations of this rule cause undefined behaviour which means that you may or may not see a diagnostic message when compiling.

There is a language difference between the following declarations at file scope, but it does not directly concern the problem with your example.

int a;

In C this is a tentative definition. It may be amalgamated with other tentative definitions in the same translation unit to form a single definition. In C++ it is always a definition (you have to use extern to declare an object without defining it) and any subsequent definitions of the same object in the same translation unit are an error.

In your example both translation units have a (conflicting) definition of xyz from their tentative definitions.

like image 168
CB Bailey Avatar answered Oct 06 '22 12:10

CB Bailey


This is caused by C++'s name mangling. From Wikipedia:

The first C++ compilers were implemented as translators to C source code, which would then be compiled by a C compiler to object code; because of this, symbol names had to conform to C identifier rules. Even later, with the emergence of compilers which produced machine code or assembly directly, the system's linker generally did not support C++ symbols, and mangling was still required.

With regards to compatibility:

In order to give compiler vendors greater freedom, the C++ standards committee decided not to dictate the implementation of name mangling, exception handling, and other implementation-specific features. The downside of this decision is that object code produced by different compilers is expected to be incompatible. There are, however, third party standards for particular machines or operating systems which attempt to standardize compilers on those platforms (for example C++ ABI[18]); some compilers adopt a secondary standard for these items.

From http://www.cs.indiana.edu/~welu/notes/node36.html the following example is given:


For example for the below C code

int foo(double*);
double bar(int, double*);

int foo (double* d) 
{
    return 1;
}

double bar (int i, double* d) 
{
    return 0.9;
}

Its symbol table would be (by dump -t)

[4]  0x18        44       2     1   0   0x2 bar
[5]  0x0         24       2     1   0   0x2 foo

For same file, if compile in g++, then the symbol table would be

[4]  0x0         24       2     1   0   0x2 _Z3fooPd
[5]  0x18        44       2     1   0   0x2 _Z3bariPd

_Z3bariPd means a function whose name is bar and whose first arg is integer and second argument is pointer to double.


like image 25
hlovdal Avatar answered Oct 06 '22 14:10

hlovdal


C++ does not allow a symbol to be defined more than once. Not sure what the C linker is doing, a good guess might be that it simply maps both definitions onto the same symbol, which would of course cause severe errors.

For porting I would try to put the contents of individual C-files into anonymous namespaces, which essentially makes the symbols different, and local to the file, so they don't clash with the same name elsewhere.

like image 1
tobing Avatar answered Oct 06 '22 13:10

tobing