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

1

1

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.

Kenric answered 9/6, 2023 at 6:45 Comment(4)
extern "C" doesn't really make any sense for variables. What is the problem using extern "C" for variables would solve? Why do you think you need it?Dropwort
@Someprogrammerdude: As you can see the names are mangled otherwise. So if you want to combine C and C++ parts / modules, it could be useful.Kenric
The standard says "Some of the properties associated with an entity with language linkage are specific to each implementation and are not described here.", and the only mention of "ill-formed" is in connection to conflicting function declarations.Kopeck
@Someprogrammerdude Wouldn't it help address namespace issues for variables? It feels that Visual C++ in this case isn't handling the differences in namespaces correctly for the variables.Midget
U
0

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

Unutterable answered 9/6, 2023 at 7:43 Comment(4)
The issue is that there is not even a warning in the case of conflicting variable declarations.Kopeck
@Kopeck I have edited the answer to address that too.Unutterable
The variables have external linkage (I think this is what the External from dumpbin means). If I exchange the order of the lines, C++ linkage wins. I edited the question to point this out.Kenric
They have external linkage if they are defined in another translation unit. Inside extern "C" {...} we have two variables defined, hence they have internal linkage.Unutterable

© 2022 - 2024 — McMap. All rights reserved.