extern “C” について

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

投稿者:

コメントを残す

メールアドレスが公開されることはありません。