[英]extern “C” inline functions
这段代码会导致未定义的行为吗?
header.h
#ifdef __cplusplus
extern "C"
{
#endif
inline int foo(int a)
{
return a * 2;
}
#ifdef __cplusplus
}
#endif
def.c
#include "header.h"
extern inline int foo(int a);
use.c
#include "header.h"
int bar(int a)
{
return foo(a + 3);
}
main.cpp
#include <stdio.h>
#include "header.h"
extern "C"
{
int bar(int a);
}
int main(int argc, char** argv)
{
printf("%d\n", foo(argc));
printf("%d\n", bar(argc));
}
这是一个程序的例子,其中必须在C和C ++中使用inline
函数。 如果删除了def.c
并且在C中没有使用foo
,它会工作吗? (这假设C编译器是C99。)
编译时,此代码有效:
gcc -std=c99 -pedantic -Wall -Wextra -c -o def.o def.c
g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp
gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c
g++ -std=c++11 -pedantic -Wall -Wextra -o extern_C_inline def.o main.o use.o
foo
仅在extern_C_inline
一次,因为编译器在不同目标文件中输出的不同版本会合并,但我想知道标准是否指定了此行为。 如果我删除foo
extern
定义并使其static
那么foo
将多次出现在extern_C_inline
,因为编译器在每个编译单元中输出它。
该程序在写入时有效,但需要def.c
以确保代码始终适用于所有编译器以及不同文件的任何优化级别组合。
因为有一个带有extern
的声明, def.c
提供了函数foo()
的外部定义,你可以用nm
确认:
$ nm def.o
0000000000000000 T foo
无论文件如何编译,该定义将始终存在于def.o
。
在use.c
有一个foo()
的内联定义 ,但是根据C标准中的6.7.4,未指定对foo()
的调用是使用内联定义还是使用外部定义(实际上是否使用了内联定义取决于文件是否已优化)。 如果编译器选择使用内联定义,它将起作用。 如果它选择不使用内联定义(例如,因为它是在没有优化的情况下编译的),那么您需要在其他文件中使用外部定义。
没有优化use.o
有一个未定义的引用:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c
$ nm use.o
0000000000000000 T bar
U foo
但是通过优化它不会:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c -O3
$ nm use.o
0000000000000000 T bar
在main.cpp
中将有一个foo()
的定义,但它通常会生成一个弱符号,因此如果在另一个对象中找到另一个定义,它可能不会被链接器保留。 如果弱符号存在,它可以满足use.o
中任何可能的引用,这需要一个外部定义,但如果编译器在main.o
联foo()
,那么它可能不会在main.o
发出任何foo()
的main.o
,所以仍然需要def.o
的定义来满足use.o
没有优化main.o
包含一个弱符号:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp
$ nm main.o
U bar
0000000000000000 W foo
0000000000000000 T main
U printf
但是,使用-O3
编译main.cpp
联对foo
的调用,并且编译器不会为其发出任何符号:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp -O3
$ nm main.o
U bar
0000000000000000 T main
U printf
所以,如果foo()
中没有内联use.o
但内联main.o
那么你需要在外部定义def.o
如果删除了def.c并且在C中没有使用foo,它会工作吗?
是。 如果foo
仅用于C ++文件,那么你不需要def.o
中foo
的外部定义,因为main.o
要么包含它自己的(弱)定义,要么内联函数。 foo.o
的定义只需要满足来自其他C代码的非内联调用foo
。
另外:允许C ++编译器在优化main.o
时跳过为foo
生成任何符号,因为C ++标准说在一个转换单元中inline
声明的函数必须在所有转换单元中内联声明,并调用inline
声明的函数必须在与调用相同的文件中提供定义。 这意味着编译器知道如果某个其他文件想要调用foo()
那么其他文件必须包含foo()
的定义,因此当编译其他文件时,编译器将能够生成另一个弱符号定义根据需要功能(或内联)。 因此,有没有必要输出foo
在main.o
如果所有调用main.o
已经被内联。
这些是来自C的不同语义,其中use.c
中的内联定义可能被编译器忽略,并且即使def.c
没有任何def.c
调用它, def.o
的外部定义def.o
必须存在。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.