我已经读了here本:

上面写道:

用内联方式定义的函数.始终发出独立的目标代码.在整个程序中,您只能编写一个这样的定义.如果要将它从其他翻译单元使用到定义它的翻译单元,您可以在头文件中放置一个声明;但它不会内联在这些翻译单元中.

然而,在我的最小可重现示例中:

Test.c

inline                                                                                                                                                                         
int foo(void)                                                                                                                                                                  
{                                                                                                                                                                              
  return 0;                                                                                                                                                                    
}                                                                                                                                                                              
                                                                                                                                                                               
int main(void)                                                                                                                                                                 
{                                                                                                                                                                              
  foo();                                                                                                                                                                       
}  

收纳

cc -std=c99 -Wall -Wextra -Wshadow -Wpedantic Test.c -o test                                                                                                                   
Undefined symbols for architecture x86_64:                                                                                                                                     
  "_foo", referenced from:                                                                                                                                                     
      _main in test-febb67.o                                                                                                                                                   
ld: symbol(s) not found for architecture x86_64                                                                                                                                
clang: error: linker command failed with exit code 1 (use -v to see invocation)                                                                                                
make: *** [Makefile:4: test] Error 1 

因此,代码似乎没有正确发出.同样的问题也出现在gcc人身上.这里发生什么事情?具体地说,我想知道,这里有什么不同:

这个可以修好它.

inline foo(void) { /* definition */ }
foo(void);

这个可以修好它.

foo(void) { /* definition */ }
inline foo(void);

我的 case 是: 不对.

inline foo(void) { /* definition */ }

我看到here可能是因为它有外部链接,但没有提供外部定义;然而,这只是main和单个翻译单位(内部)中的引用.这个符号在哪里没有被解析?为什么?一定是main的电话打来的.

我发现当-O2打开时,没有问题,这是因为代码不是最初发出的,默认情况下也不是内联的.

This没有回答我的问题.我不是问static inline修复的问题,只是问为什么它在这个 case 中被区别对待,而不是inline,这一点我仍然不明白.为什么这总是会导致排放?

我想首先理解为什么this是一个问题,因为我读到它会发出代码.这一点在标准中有明确的体现吗?

推荐答案

这一点在标准中有明确的体现吗?

这就是C语言规范对它的描述:

任何具有内部链接的函数都可以是内联函数.为. 函数,则适用以下限制:如果 函数是用inline函数说明符声明的,则它将 也在同一翻译单元中定义.如果所有文件作用域 翻译单元中函数的声明包括inline 不带extern的函数说明符,则其中的定义 翻译单位是inline definition.An inline definition does not provide an external definition for the function,而不是 禁止在另一个翻译单位中使用外部定义.内联 定义提供了外部定义的替代方法,外部定义是 翻译器可用于实现对同一 翻译单位.未指明是否调用该函数 使用内联定义或外部定义.

(C23 6.7.4/7;增加强调)

external definition是一个外部声明,它也是 函数的定义(内联定义除外)或 对象.如果使用外部链接声明的标识符在 表达式(非[...]),somewhere in the entire program there shall be exactly one external definition for the identifier[...]

(C23 6.9/5;增加强调)

这对您的代码来说是这样的:

  • 由于在不带static的文件范围内声明,函数foo具有外部链接.

  • 因为foo被声明为inline而不是explicitly extern,所以提供的定义是内联定义,而不是外部定义.

  • 你的main()调用foo,它有外部链接,所以在整个程序的某个地方需要有该函数的外部定义,但没有.因此,你的程序是不一致的.

因此,代码似乎没有正确发出.

No, you've got that mixed up. Rather: the code is properly not being emitted. An inline definition is not an external definition, 和 the compiler needs to leave room for an external definition to be provided by another translation unit.

GCC is not required to reject incorrect programs, 和 it's reasonable to imagine that it might figure out what to do with yours, but it is completely within its rights 和 the spec to reject the program. That it accepts the program when you enable optimization is fully consistent.

这个可以修好它.

inline foo(void) { /* definition */ }
foo(void);

是.现在不再满足条件"如果转换单元中某个函数的所有文件作用域声明都包含不带externinline函数说明符",因此该定义是外部定义,而不是内联定义.

这个可以修好它.

foo(void) { /* definition */ }
inline foo(void);

一样的.现在foo‘S的定义是一个外在的定义.

另一个同样的解决方案是:

extern inline foo(void) { /* definition */ }

当然,你可以通过提供foo个内部链接来避免这个问题.这有几种变体,但这只是其中之一:

static inline foo(void) { /* definition */ }

.

If you think this is all a bit weird, then you're right. It's usually best to avoid the issue by giving your inline functions internal linkage (by declaring them static). But if you don't do that, then a reasonable usage pattern is similar to that for declaring 和 defining external variables:

  • put the (inline) definition in a header.
  • choose one translation unit to provide the external definition. In this TU,
    • #include the header, 和
    • redeclare the function with the extern specifier.

That gets you the needed external definition without duplicating any code, but I don't see much to recommend it over simply making the definition static.

C++相关问答推荐

为指针 struct 创建宏

数组元素的编号索引

使用单个字节内的位字段

exit(EXIT_FAILURE):Tcl C API类似功能

如何判断宏参数是否为C语言中的整型文字

DPDK-DumpCap不捕获端口上的传入数据包

为什么双重打印与C中的float具有不同的大小时具有相同的值?

空指针的运行时强制转换

以前版本的tty_ldisc_ops.ioctl()是否也需要文件参数?

警告:C++中数组下标的类型为‘char’[-Wchar-subpts]

使用错误的命令执行程序

如何在下面的C代码中正确管理内存?

从uint8_t*转换为char*可接受

为什么我从CSV文件中进行排序和搜索的代码没有显示数据的所有结果?

仅从限制指针参数声明推断非混叠

从Raku nativecall调用时精度不同

如何解释数组中的*(ptr)和*(ptr+2)?

I';我试着从.txt文件中读取文本,并用c计算其中的单词数量

execve 不给出which命令的输出

无法理解 fgets 输出