なぜ 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” ということに注意!