なぜ extern “C” を使うのか。
メモメモ。。
C++とCではラベルの命名規則が違うようです。
Cで
test(){};
をコンパイルするとアセンブリでは _test: ラベルが生成されます
C++で
test(){};
をコンパイルするとアセンブリでは __Z4testv: ラベルが生成されます
C++からtest関数を呼ぼうとすると__Z4testv:を探します。
すると、当然にラベルが存在しないのでリンカエラーが発生します。
そこで extern “C” を使うと、C++からtest関数を呼ぼうとすると_test:を探します。
すると、ラベルが存在するので問題なくリンク出来ます。
サンプル
test.h
/* C Header */ #ifndef TEST_H_ #define TEST_H_ #ifdef __cplusplus extern "C" { #endif void test(); #ifdef __cplusplus } #endif #endif /* TEST_H_ */
test.c
/* C Source */ #include "test.h" void test() { }
testp.cpp
/* C++ Source */ #include "test.h" void aaa() { } int main() { aaa(); test(); return 0; }
test.s
.text .align 2 .globl _test .def _test; .scl 2; .type 32; .endef _test: pushl %ebp movl %esp, %ebp popl %ebp ret
■ extern “C” あり
testp.s
.text .align 2 .globl __Z3aaav .def __Z3aaav; .scl 2; .type 32; .endef __Z3aaav: pushl %ebp movl %esp, %ebp popl %ebp ret .def ___main; .scl 2; .type 32; .endef .align 2 .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main call __Z3aaav call _test movl $0, %eax leave ret .def _test; .scl 3; .type 32; .endef
■ extern “C” なし
testp.s
.text .align 2 .globl __Z3aaav .def __Z3aaav; .scl 2; .type 32; .endef __Z3aaav: pushl %ebp movl %esp, %ebp popl %ebp ret .def ___main; .scl 2; .type 32; .endef .align 2 .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main call __Z3aaav call __Z4testv movl $0, %eax leave ret .def __Z4testv; .scl 3; .type 32; .endef
C++では同じ関数名が利用できるので命名規則が複雑になってるようです。
ちなみに
extern “c” じゃなくて
extenn “C” ということに注意!