3

I am very curious about what happens during linking, and, during my research in this area I have stabbed upon this code

#ifdef __cplusplus
extern “C” { 
#endif

extern double reciprocal (int i);

#ifdef __cplusplus
}
#endif

The code was in some header file, which was include by .c and .cpp source files of one program. It's a declaration of a function, which is then defined in .cpp file. Why does it work? I mean, during the compilation of the .cpp file this will turn into

extern "C" {
    extern double reciprocal (int i);
}

The outer extern both makes the function visible in the global scope and converts the C++ style of function names into C one. But there also is an inner extern. Is it OK the function is externed twice?

2
  • 1
    Ignoring the pre-processing #ifdefs and just looking a the second snippet, the former is language linkage, with as you write, the main intent to make the some entities therein (function types, as well as function names and variables with external linkage and variables) to C language linkage, with one main effect that these entities will not have mangled names, and will moreover be placed in global namespace (since there are no namespaces in the C ABI). ... Commented Apr 27, 2020 at 20:05
  • ... The inner extern is not a language linkage specifier but is a storage class specifier, and it will have no effect on the synergy between these two, as reciprocal already has external linkage even without extern (which in turn implies that it has language linkage, making it possibly to link translation units from other languages). Commented Apr 27, 2020 at 20:05

1 Answer 1

4

The c++ language is allergic to adding new keywords so some get reused to mean different things. extern is one of these re-used keywords. It has 3 possible meanings:

  1. external linkage - the variable or function is defined somewhere else
  2. language linkage - the variable or function is defined in an "external" language
  3. explicit template instantiation declaration

In your case you are using 1 and 2. extern "C" declares that the code has "C" rather than the default "C++" linkage. This also implies external linkage so in pure C++ code you can just write:

extern "C" {
    double reciprocal (int i);
}

and reciprocal will be automatically be marked extern. Adding an extra extern has no effect and is required for the C version which doesn't have the extern "C" wrapper.

Note that if you are using single declaration version of extern "C" then using a second extern is not valid:

extern "C" extern double reciprocal (int i);

As the second extern is not required the correct declaration is:

extern "C" double reciprocal (int i);
Sign up to request clarification or add additional context in comments.

7 Comments

"[...] and reciprocal will be automatically be marked extern" - I don't believe this is accurate, what would "marked extern" even mean in this context, as we have just established that the extern keywords is heavily overloaded in C++? The language linkage blocks just applies C language linkage to e.g. function names encompassed by its braces block that have external linkage - it does not automatically mark it as extern. In some sense, it is, for such a name, comparable to marking the name with extern "C".
As an (contrived) exercise, we could even declare reciprocal as static after which the extern "C" block would have no effect on that particular function name, as it no longer has external linkage.
@dfri yes, you don't even need to mark it as static, the extern "C" declaration of a function has to be the first declaration: "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. ": godbolt.org/z/AeQUgu
My example was applied to extern "C" { declaration-seq(optional) }, which in itself is not a declaration, but which applies language linkage. If e.g. one of the function declarations within declaration-seq is marked by static, the extern "C" { ... } block will not apply C language linkage to it. I believe your quite covers the redeclaration beyond that of the declaration within the extern "C" { ... } block, or when using the at-declaration language linkage form extern "C" declaration.
gcc still applies c linkage here: godbolt.org/z/EXcTH8
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.