qbt*_*937 6 c c++ inline-functions
这段代码会导致未定义的行为吗?
header.h
#ifdef __cplusplus
extern "C"
{
#endif
inline int foo(int a)
{
return a * 2;
}
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
def.c
#include "header.h"
extern inline int foo(int a);
Run Code Online (Sandbox Code Playgroud)
use.c
#include "header.h"
int bar(int a)
{
return foo(a + 3);
}
Run Code Online (Sandbox Code Playgroud)
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));
}
Run Code Online (Sandbox Code Playgroud)
这是一个程序的例子,其中一个inline函数必须在C和C++中使用.如果def.c被删除并且foo没有在C中使用它会起作用吗?(这假设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
Run Code Online (Sandbox Code Playgroud)
foo只是extern_C_inline一次,因为编译器在不同的目标文件中输出的不同版本被合并,但我想知道这个行为是否由标准指定.如果我删除了extern定义foo并将其删除,static那么foo将extern_C_inline多次出现,因为编译器在每个编译单元中输出它.
该程序在编写时有效,但def.c需要确保代码始终适用于所有编译器以及不同文件的任何优化级别组合.
因为有一个声明,extern它def.c提供了函数的外部定义foo(),您可以通过以下方式确认nm:
$ nm def.o
0000000000000000 T foo
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
但是通过优化它不会:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c -O3
$ nm use.o
0000000000000000 T bar
Run Code Online (Sandbox Code Playgroud)
在main.cpp将有一个定义,foo()但它通常会生成一个弱符号,因此如果在另一个对象中找到另一个定义,它可能不会被链接器保留.如果存在弱符号,则它可以满足任何可能的引用,use.o因为它需要外部定义,但如果编译器内联foo(),main.o那么它可能不会发出任何foo()in 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
Run Code Online (Sandbox Code Playgroud)
但是,编译main.cpp与-O3内联调用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
Run Code Online (Sandbox Code Playgroud)
所以,如果foo()是没有的内联use.o,但被于内联main.o,那么你需要在外部定义def.o
如果删除了def.c并且在C中没有使用foo,它会工作吗?
是.如果foo仅在C++文件中使用,那么您不需要fooin 的外部定义,def.o因为它们main.o包含其自己的(弱)定义或将内联函数.foo.o仅需要满足foo来自其他C代码的非内联调用的定义.
另外:允许C++编译器foo在优化时跳过生成任何符号,main.o因为C++标准规定inline在一个转换单元中声明的函数必须在所有转换单元中内联声明,并且要调用声明inline的函数,该定义必须在与呼叫相同的文件.这意味着编译器知道如果某个其他文件想要调用foo()那么其他文件必须包含定义foo(),那么当编译其他文件时,编译器将能够生成该函数的另一个弱符号定义(或内联它)如所须.因此foo,main.o如果所有的调用main.o都已内联,则无需输入.
这些是来自C的不同语义,其中内联定义use.c可能被编译器忽略,并且外部定义def.o必须存在,即使def.c调用它也没有.