extern "C": Why does Visual C++ behave different on conflicting linkage specs for variables vs. for functions?

104 Views Asked by At

If a variable is declared somewhere without extern "C" (e.g. in a header file) and afterwards defined with extern "C", then the Visual C++ compiler compiles it with C++ linkage without further notice:

extern IntStruct ifcStruct;
extern int       ifcVar;
/* ... */

extern "C"
{
IntStruct ifcStruct;
int       ifcVar = 0;
}

dumpbin /symbols test.obj shows C++ symbols with mangled names:

00C 00000000 SECT4  notype       External     | ?ifcStruct@@3UIntStruct@@A (struct IntStruct ifcStruct)
00D 00000008 SECT4  notype       External     | ?ifcVar@@3HA (int ifcVar)

However, when a function is declared without and then defined with extern "C"

extern void ifcf ();
/* ... */
extern "C" void ifcf () {}

then the Visual C++ compiler gives a distinct error message:

test.cpp(20): error C2732: linkage specification contradicts earlier specification for 'ifcf'
test.cpp(20): note: see declaration of 'ifcf'

Is there an explaination for this difference that arises from the standard?


It makes no difference whether the extern "C" is used with or without {...}.
And it makes no difference whether the function declaration is done with or without extern.
The variable declaration needs the extern - otherwise it is "redefinition". However, there is no difference whether the extern is specified at the declaration, or at the definition, or both. In all cases the first occurence defines the language linkage.


edit: As Karen stated, the behavior on functions is described by Microsoft,
as well as on cppreference.com:

A function can be re-declared without a linkage specification after it was declared with a language specification, the second declaration will reuse the first language linkage. The opposite is not true: if the first declaration has no language linkage, it is assumed "C++", and redeclaring with another language is an error.

1

There are 1 best solutions below

4
Karen Baghdasaryan On

From here

If a function has more than one linkage specification, they must agree. It's an error to declare functions as having both C and C++ linkage. Furthermore, if two declarations for a function occur in a program, one with a linkage specification and one without, the declaration with the linkage specification must be first. Any redundant declarations of functions that already have linkage specification are given the linkage specified in the first declaration.

As you can see, according to the quote, the declaration of function with extern "C" specifier should appear first appear first.

extern "C" void ifcf ();
/* ... */
extern void ifcf () {} // OK


////////////////////////////


extern void ifcf ();
/* ... */
extern "C" void ifcf () {} // extern "C" is after the first declaration. NOT OK

However, the situation is different with extern "C" {...}

The first tells the compiler that if there is a name or symbol with external linkage inside the blocks, use C naming, otherwise use C++ name mangling. But as far as you have defined the names inside extern "C" {...} they have internal linkage, hence no C naming is used. It can be seen from 9.11.5

Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not establish a scope. A linkage-specification shall occur only in namespace scope (6.4). In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification