当前位置: 首页 > 知识库问答 >
问题:

GCC编译器在优化级别O0下无法找到内联函数定义的链接问题?

陆耀
2024-05-13

GCC编译器在优化级别O0下无法找到内联函数定义的链接问题

我在gcc编译器下写了如下代码:

/* InlineMain.c */#include <stdio.h>inline  void Function(){    printf("[Function]========= Get!!!\n");}int main() {    Function();        return 0;}

然后在不开启优化(即-O0)的情况下,会报链接错误,找不到符号"Function":

  • 备注:在开启优化O1以上的情况下是可以正常编译的,编译器会将函数体进行替换

    $ gcc INlineMain.c   /usr/bin/ld: /tmp/ccQuzijl.o: in function `main':INlineMain.c:(.text+0xe): undefined reference to `Function'collect2: error: ld returned 1 exit status

我试着编译并查看了对应的汇编代码:

$ gcc INlineMain.c -S
$ cat INlineMain.s
        .file   "INlineMain.c"        .text        .globl  main        .type   main, @functionmain:.LFB1:        .cfi_startproc        endbr64        pushq   %rbp        .cfi_def_cfa_offset 16        .cfi_offset 6, -16        movq    %rsp, %rbp        .cfi_def_cfa_register 6        movl    $0, %eax        call    Function@PLT        movl    $0, %eax        popq    %rbp        .cfi_def_cfa 7, 8        ret        .cfi_endproc.LFE1:        .size   main, .-main        .ident  "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"        .section        .note.GNU-stack,"",@progbits        .section        .note.gnu.property,"a"        .align 8        .long   1f - 0f        .long   4f - 1f        .long   50:        .string "GNU"1:        .align 8        .long   0xc0000002        .long   3f - 2f2:        .long   0x33:        .align 84:

然后我就发现一件非常让我匪夷所思的事情,就是整一个Function函数主体都消失了!!!
但是也没有被内联替换到被调用的地方,不难发现,在main函数中,依旧是:

call Function@plt,

即把Function函数当做plt表里的函数(也就是外部函数调用) ,
看上去就像是在处理Function函数体的时候编译器把它当做是要内联的函数处理,于是就把整个函数体给删除了,但是在处理函数调用的时候又没有把函数体进行替换,而是把它当做正常的函数调用处理,就好像是处理到中途反悔了一样,有没有大佬能解释一下是为什么?

  • 备注:我的平台是ubuntu22.04,gcc编译器是默认的版本

共有1个答案

樊琦
2024-05-13

C99 对 inline 有一个这样的说明:

Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

一个函数可以有一个 inline definition 和一个 external definition ,而且编译器可以自由选择在调用时使用哪一种。注意不是去看哪一种存在,而是先决定用哪一种,再去看它是不是存在。

这里出错是因为编译器决定用 external definition (-O0 阻止了内连),但是程序中只有一个 inline definition ,并没有 external definition ,于是出错了。

注意 C++ 中 inline 的用法并不是这样的,gcc 也有其它的 inline 模式。

另可参考:
https://gcc.gnu.org/gcc-5/porting_to.html (Different semantics for inline functions)

 类似资料:
  • 我有一个函数定义为 (是映射到英特尔MIC体系结构上SIMD寄存器的本机数据类型) 由于这个函数相当短并且经常被调用,我希望它在每次调用时都内联。但是英特尔的编译器似乎不愿意内联这个函数,即使在我使用 - 和 选项之后也是如此。它报告说“Forceinline不被授予呼叫......”编译时。由于我必须使用一些编译器特定的功能,例如类型,英特尔编译器是我唯一的选择。 更多信息: 文件结构非常简单。

  • 问题内容: 说,我想在gcc的内联汇编中调用具有以下签名的函数。我怎样才能做到这一点? 问题答案: 通常,您会想要做类似的事情 也就是说,您根本不需要在嵌入式asm中进行函数调用。这样,您不必担心调用约定或堆栈框架管理的细节。

  • 问题内容: 我试图得到以下消息: 好吧,有一个开放的jdk,我也下载了另一个。我尝试将JAVA_HOME指向两者,现在已设置: 我还尝试选择其中一种打开方式,但是其中的不同jdk版本出现相同的错误。 我该如何解决?提前致谢。 问题答案: 似乎您的PATH未正确选择…“ echo $ PATH”的输出是否包含javac所在的目录?我建议如下: 打开终端并执行: 如果javac -version仍然不

  • gcc 是 GNU 推出的功能强大、性能优越的多平台编译器,是 GNU 的代表作品之一。它能将C、C++语言源程序、汇编语言源程序和目标程序编译、链接成可执行文件,如果没有给出可执行文件的名字,gcc 将生成一个名为 a.out 的文件。 gcc 通过后缀来区分输入文件的类型: 后缀 类型 .c C语言源代码文件 .a 由目标文件构成的档案库文件 .C|.cc|.cxx C++源代码文件 .h 程

  • 我试图用自定义比较器定义优先级队列,如下所示: 这就是显示的编译错误 我还尝试在测试类中声明另一个比较函数,但没有效果。为什么主函数中的优先级队列编译而类中的优先级队列不编译?为比较器定义专用类是这里唯一的工作吗?谢谢你。

  • 我想在RHEL5中安装Apache。在配置httpd-2.4.2时出现以下错误: 于是我下载了gcc-4.7.0,尝试配置。同样的错误又来了。 我不能使用。所以请帮助解决这个问题。