After reading about extern and static, I am confused to come across the code which has the line below:
extern "C" static void* foo(int* a){
return foo1(a);
}
Why does this not generate any error?
You cannot use extern and static together they are mutually exclusive. You need to use only extern if you need External Linkage.
A static function in C is a function that has a scope that is limited to its object file. This means that the static function is only visible in its object file. A function can be declared as static function by placing the static keyword before the function name.
defines a variable j with external linkage; the extern keyword is redundant here. extern void f(); declares that there is a function f taking no arguments and with no return value defined somewhere in the program; extern is redundant, but sometimes considered good style.
extern "C" specifies that the function is defined elsewhere and uses the C-language calling convention. The extern "C" modifier may also be applied to multiple function declarations in a block. In a template declaration, extern specifies that the template has already been instantiated elsewhere.
The following also compiles and does the same thing as your line:
extern "C" {
static void* foo(int* a){
return foo1(a);
}
}
The static
means that foo()
will only be available in file scope, and it overrides the extern "C"
when it comes to linkage. Normally, extern "C"
effects the name of the function used by the linker if/when it is exported, so that the function could be called from other object files when the entire program is linked. Usually, this is used when either you want to link to an object file built from C source where foo()
was defined, or where you want to define foo()
so that C code can call it. However, the static
causes foo
to simply not be exported at all, so it basically doesn't even get a name (it has internal, not external linkage).
extern "C"
also has a secondary effect. It also becomes part of the type of foo
. That is, C++ code will see foo
as having type extern "C" void(int*)
. Basically, this controls calling convention. A C++ compiler may e.g. arrange arguments differently in registers/on the stack than a C compiler might. Making foo
be a C function means that it will use the C conventions and not the C++ conventions. This makes it safe to e.g. pass a function pointer to foo
to a C function that expects a pointer to a C function. For example, the standard library has
extern "C" typedef int C_CMP(void const*, void const*);
extern "C++" typedef int CXX_CMP(void const*, void const*);
void std::qsort(void *, std::size_t, std::size_t, C_CMP);
void std::qsort(void *, std::size_t, std::size_t, CXX_CMP);
With the extern "C"
, &foo
is passed to the first overload, but without it/with extern "C++"
, it is passed to the second. It would not be safe to declare foo
without extern "C"
and then try to pass it into a C function that expects a pointer to a C function. It would probably work, but it might also break horribly. Add the extern "C"
and it becomes correct—you're safe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With