繁体   English   中英

extern“C”内联函数

[英]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.ofoo() ,那么它可能不会在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.omain.o那么你需要在外部定义def.o

如果删除了def.c并且在C中没有使用foo,它会工作吗?

是。 如果foo仅用于C ++文件,那么你不需要def.ofoo的外部定义,因为main.o要么包含它自己的(弱)定义,要么内联函数。 foo.o的定义只需要满足来自其他C代码的非内联调用foo


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

这些是来自C的不同语义,其中use.c中的内联定义可能被编译器忽略,并且即使def.c没有任何def.c调用它, def.o的外部定义def.o必须存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM