15

So, while being schooled by James Kanze and Loki Astari about C linkage, I was wondering about this:

extern "C" int foo1 (void (*)());
extern "C" { int foo2 (void (*)()); }

After my schooling, I think it must be that foo1 only takes a function pointer with C++ linkage, while foo2 only takes a function pointer with C linkage. Is my understanding correct? Are there specific references in the C++ standard that explain the differences in my example above?

Edit: To make it easier for everyone to follow along here's a pastebin with the relevant part from the C++ 11 draft standard.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193

3 Answers3

10

foo1 takes a pointer to a C function as shown in [dcl.link] 7.5p4

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. [Example:

extern "C" void f1(void(*pf)(int));
                                                                 // the name f1 and its function type have C language
                                                                 // linkage; pf is a pointer to a C function

The example applies directly to foo1 and the added emphasis highlights what I think is the reason. The function's parameter lists contains a function declarator for a parameter, and all function declarators are affected by the linkage specification. This applies to both braced and non-braced linkage specifications.

Some differences when not using braces are that names are automatically extern and explicit use of a storage specifier is prohibited.

extern "C" int i; // not a definition

int main() {
    i = 1; // error, no definition
}

extern "C" static void g(); // error

As an example of where this difference matters, consider a header containing the following:

extern "C" int a;
extern "C" double b;
extern "C" char c;

Someone might be tempted to change this to:

extern "C" {
    int a;
    double b;
    char c;
}

But that would be incorrect because that converts the declarations into definitions. Instead the correct code using extern "C" {} is:

extern "C" {
    extern int a;
    extern double b;
    extern char c;
}
bames53
  • 86,085
  • 15
  • 179
  • 244
  • I guess it kind of makes sense that it is impossible to define a function with C linkage to take a callback function with C++ linkage, but I can't see anything in the wording that actually states that. Did you? – jxh Aug 08 '12 at 23:10
  • It's entirely possible to have a function with C linkage take a pointer to a function with C++ linkage: `extern "C++" typedef void (*CPPFUNC)(); extern "C" void foo(CPPFUNC);` – bames53 Aug 08 '12 at 23:25
  • Ah, thanks. It might be tricky for it to actually call it though (unless it was implemented in C++ ;-). Answer accepted. – jxh Aug 08 '12 at 23:27
  • I think this is wrong! the `extern "C"` is for declaring that a function should not contain the parameter types in the link name (name mangled) that is the way C++ do function overloading. This way C++ can use plain C libraries, like stdlib. – epatel Aug 08 '12 at 23:34
  • @epatel The C++ standard is pretty explicit about this. See clause 7.5 [dcl.link]. Linkage can be more than just name mangling. – bames53 Aug 08 '12 at 23:38
  • @bames53 You mention ABI. The ABI shouldn't differ between C and C++ (on the same platform and using the same tool provider). The ABI is about parameter placements on the stack etc. http://en.wikipedia.org/wiki/Application_binary_interface I even think most compilers would allow using static class methods as callbacks to plain `C` functions as `qsort(..)`. Actually I think the keyword `pascal` is much more interesting. – epatel Aug 08 '12 at 23:49
  • 1
    @epatel There's no requirement that the C and C++ ABI's be the same and the standard is quite explicit in that function types have a language linkage separate from the function's name. One example it specifically calls out is calling conventions. – bames53 Aug 09 '12 at 00:02
  • @bames53 Sure, I didn't say "must not"! But, I have never seen a system where they differ. I think you are confusing linkage with runtime. ABI is about runtime. Linkage is either compile time or dynamically handled by the OS (language agnostic) prior runtime. Name mangling is about linkage. You are referencing "linkage". We are talking about C/C++ which is compiled into executables? Don't know if the C++ specs require that. – epatel Aug 09 '12 at 00:12
  • @epatel: Consider this from the first paragraph to section 7.5: Two function types with different language linkages are distinct types even if they are otherwise identical. This means the linkage is part of the type. So a pointer to C function is different from pointer to C++ function. Since it is bound to the type, it is more than just name mangling. – jxh Aug 09 '12 at 00:37
  • @user315052 I believe the spec make room for implementation technics. Name mangling being one. I imagine when they "talk" about linkage they have come closer to the implementation issues as this part is about accessing external things (but still they "talk" about linkage which shouldn't be a language issue unless you have a "compiler"). I can't see any reason to leave a system wide ABI just for C++, and have never seen it. Most fun was the SGI C++ compiler that didn't require method bodies in header files for templates (could cause some nasty link bugs). Well, I'll end here...over and out... – epatel Aug 09 '12 at 01:00
2

The braces are used when you have many declarations and definitions. Often you can see a start and end in header files for C code to be usable in C++

#ifdef __cplusplus
extern "C" {
#endif

// C stuff here to be available for C++ code

#ifdef __cplusplus
}
#endif

I can recommend reading about "name mangling" http://en.wikipedia.org/wiki/Name_mangling The extern "C" is a key to fallback to C linkage name conventions.

epatel
  • 45,805
  • 17
  • 110
  • 144
1
extern "C" int foo1 (void (*)());
extern "C" { int foo2 (void (*)()); }

Those are the same. The main reason to use braces is if you have more than one function, e.g:

extern "C" int foo1 (void (*)());
extern "C" int foo2 (void (*)());
extern "C" int foo3 (void (*)());
extern "C" int foo4 (void (*)());

that can be written more simply as:

extern "C" {
    int foo1 (void (*)());
    int foo2 (void (*)());
    int foo3 (void (*)());
    int foo4 (void (*)());
}

Additionally, if you're trying to make one header file that works with both C and C++, you might want to write that as:

#ifdef __cplusplus
extern "C" {
#endif

    int foo1 (void (*)());
    int foo2 (void (*)());
    int foo3 (void (*)());
    int foo4 (void (*)());

#ifdef __cplusplus
}
#endif

P.S. I'm not aware of any compilers where there's a difference between "C++ linkage" or "C linkage" for function pointers. When we talk about C or C++ linkage, we're talking about how the name gets mangled by the compiler. For a function pointer, you're passing a pointer, so the name is irrelevant. It's important that the calling convention is the same, but it usually is the same for C and C++, since people freely mix those languages.

user9876
  • 10,954
  • 6
  • 44
  • 66
  • The standard discusses "C" and "C++" linkage for both names and for function types. It's used where C and C++ ABI's differ from each other. – bames53 Aug 08 '12 at 23:35
  • I've edited the answer to say that "I'm not aware of any compilers where there's a difference" instead of "There is no difference". For a new programmer, with normal compilers, there is no difference that matters. – user9876 Aug 09 '12 at 11:43