extern “C”

You may have seen following C++ code somewhere.

[sourcecode language=”cpp”]
extern "C"{
….
}
[/sourcecode]

Why do we need the extern “C”?

The answer is available in this post. The idea is, C++ compiler treat c++ differently from C. A function void f(int i) in C code is translated into _f in assembly, while the same function in C++ code will be translated into __Z1fi(the i at the end means first parameter is i, but I am not sure what does __Z1 seems represent return type). Compiler determin whether the code is C or C++ by looking at file extension only(.c for c file, .cpp for c++ file). C++ code is treated differently because C++ language support function overloading. That is to say, void f(int n) and void f(char c) are two different function because they have different parameter type. Compiler implement this by using different names for these two functions: including parameter type into function name. This method works fine, but when you want to call a C function in your C++ code, and the C function is already compilede as C code, then you have trouble.

[sourcecode language=”cpp”]
// sqr.c
int sqr(int n){
return n*n;
}
[/sourcecode]
[sourcecode language=”cpp”]
// main.c
#include<stdio.h>
int sqr(int n); //declaration
int main(){
printf("%d\n",sqr(10));
return 0;
}
[/sourcecode]
The code above works fine. However, if you rename “main.c” into “main.cpp”, then you have problem: compiler(actually linker) complains that “int sqrt(int) is not defined”. This is because, as a c++ function, “sqr” in “main.cpp” is translated into “__Z3sqri”, while as C code, “sqr” in “sqr.c” is translated into “_sqr”. Thus, linker cannot find the function “int sqrt(int)”. To solve this problem, we can use extern “C”{} to enclose sqr function declaration, so that the function name is translated into C style.
[sourcecode language=”cpp”]
// main.cpp
#include<stdio.h>
extern "C"{
int sqr(int n); //declaration
}
int main(){
printf("%d\n",sqr(10));
return 0;
}
[/sourcecode]

Please compile and link above code using g++ instead of gcc, or else you may get “undefined reference to `__gxx_personality_v0′” problem.

You may ask why functions declared in “stdio.h” works well for both C and C++ code? You can check out preprocessor’s output:

[sourcecode language=”cpp”]
//dummy c++ code
#include<stdio.h>
int main(){
return 0;
}
[/sourcecode]
[sourcecode language=”cpp”]
extern "C" {
……
int __attribute__((__cdecl__)) fscanf (FILE *, const char *, …) __attribute__ ((__format__ (__scanf__, 2, 3)));

int __attribute__((__cdecl__)) printf (const char *, …) __attribute__ ((__format__ (__printf__, 1, 2)));

int __attribute__((__cdecl__)) scanf (const char *, …) __attribute__ ((__format__ (__scanf__, 1, 2)));
……
}
[/sourcecode]

The output of preprocessor use extern “C” to enclose all standard C library function declaration. However, you will not be able to find extern “C” if you change file extension to .c. Stanfdard library uses following trick to do this:

[sourcecode language=”cpp”]
// /usr/include/sys/cdefs.h
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
[/sourcecode]

All C library header files include this “cdefs.h”, and use __BEGIN_DECLS and __END_DECLS to enclose function declarations.

CategoriesC

One Reply to “extern “C””

Leave a Reply

Your email address will not be published.