Reputation: 70402
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.
Upvotes: 15
Views: 1965
Reputation: 88155
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;
}
Upvotes: 10
Reputation: 11102
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.
Upvotes: 1
Reputation: 46051
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.
Upvotes: 2