gpt4 book ai didi

c++ - extern "C"内联函数

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:34:26 25 4
gpt4 key购买 nike

这段代码会导致未定义的行为吗?

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 被删除并且 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

foo 只在 extern_C_inline 中出现一次,因为编译器在不同目标文件中输出的不同版本被合并了,但我想知道这种行为是否由标准。如果我删除 fooextern 定义并使其成为 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 有一个 undefined reference :

$ 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 中内联 foo()。 o 那么它可能不会在 main.o 中发出任何 foo() 的定义,因此 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

中定义外部

Would it work if def.c was removed and foo was not used in C?

是的。如果 foo 仅在 C++ 文件中使用,那么您不需要在 def.o 中对 foo 进行外部定义,因为 main. o 要么包含自己的(弱)定义,要么将内联函数。 foo.o 中的定义只需要满足从其他 C 代码对 foo 的非内联调用。


旁白:在优化 main.o 时,允许 C++ 编译器跳过为 foo 生成任何符号,因为 C++ 标准规定函数声明为 inline 在一个翻译单元中必须在 所有 翻译单元中声明为内联,并且要调用声明为 inline 的函数,定义必须在与调用相同的文件中可用。这意味着编译器知道如果其他文件想要调用 foo(),那么其他文件必须包含 foo() 的定义,因此,当编译其他文件时,编译器将能够根据需要生成函数的另一个弱符号定义(或将其内联)。因此,如果 main.o 中的所有调用都已内联,则无需在 main.o 中输出 foo

这些是与 C 不同的语义,use.c 中的内联定义可能会被编译器忽略,而 def.o 中的外部定义甚至必须存在如果 def.c 中没有任何内容调用它。

关于c++ - extern "C"内联函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26620231/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com