我对C99中的inline感到困惑。

这是我想要的:

  • 我希望我的函数在任何地方都可以内联,而不仅限于一个翻译单元(或一个编译单元,一个.c文件)。
  • 我希望函数的地址一致。如果将函数的地址保存在函数指针中,那么我希望可以从指针中调用该函数,并且我不想在不同的转换单元中复制相同的函数(基本上,我的意思是没有static inline)。

  • C++ inline正是这样做的。

    但是(如果我错了,请纠正我)在C99中无法实现此行为。

    我可以使用static inline,但是会导致重复(同一函数在不同翻译单元中的地址不同)。我不要这个重复。

    所以,这是我的问题:
  • 在C99中inline背后的想法是什么?
  • 这种设计比C++的方法有什么好处?

  • 引用:
  • 这是一个高度表达C99 inline的链接,但我不明白为什么。这个“仅在一个编译单元中”的限制真的那么好吗? http://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/
  • 这是C99 inline的基本原理。我已经读过,但是我听不懂。 Is "inline" without "static" or "extern" ever useful in C99?
  • 一个不错的文章,提供了使用inline函数的策略。 http://www.greenend.org.uk/rjk/tech/inline.html

  • 答案摘要

    如何在C99中获得C++ inline行为(是的,我们可以)

    head.h
    #ifndef __HEAD_H__
    #define __HEAD_H__
    
    inline int my_max(int x, int y) {
        return (x>y) ? (x) : (y);
    }
    
    void call_and_print_addr();
    
    #endif
    

    src.c
    #include "head.h"
    #include <stdio.h>
    
    // This is necessary! And it should occurs and only occurs in one [.c] file
    extern inline int my_max(int x, int y);
    
    void call_and_print_addr() {
        printf("%d %u\n", my_max(10, 100), (unsigned int)my_max);
    }
    

    main.c
    #include <stdio.h>
    #include "head.h"
    
    int main() {
        printf("%d %u\n", my_max(10, 100), (unsigned int)my_max);
        call_and_print_addr();
    
        return 0;
    }
    

    编译:gcc -O3 main.c src.c -std=c99使用以下命令检查程序集:gcc -O3 -S main.c src.c -std=c99,您会发现my_maxcall_and_print_addr()都内联了main()

    实际上,这与ref 1和ref 3给出的指令完全相同。我怎么了?

    我使用的是GCC (3.4.5)的版本过旧,它给出了“my_max的多个定义”错误消息,这是我如此困惑的真正原因。耻辱。

    C99和C++ inline之间的区别

    实际上,您可以通过g++编译上面的示例:g++ main.c src.c
    extern inline int my_max(int x, int y);
    

    在C++中是多余的,但在C99中是必需的。

    那么在C99中它做什么呢?

    同样,使用gcc -O3 -S main.c src.c -std=c99,您将在src.s中找到类似的内容:

    _my_max:
        movl    4(%esp), %eax
        movl    8(%esp), %edx
        cmpl    %eax, %edx
        cmovge  %edx, %eax
        ret
        .section .rdata,"dr"
    

    如果剪切extern inline int my_max(int x, int y);并将其粘贴到main.c中,则会在main.s中找到这些汇编代码。

    因此,通过extern inline,您告诉编译器将在何处定义和编译真正的函数my_max(),您可以通过其地址来调用它。

    现在回头看一下C++,我们无法指定它。我们永远不会知道my_max()会在哪里,这就是@Potatoswatter的“模糊链接”。

    正如@Adriano所说,大多数时候,我们并不关心这个细节,但是C99确实消除了歧义。

    最佳答案

    要获得类似C++的行为,您需要为每个TU赋予可能内联的调用inline定义,并为一个TU提供一个外部可见的定义。这正是C标准相关部分(功能说明符)中的示例1所说明的内容。 (在该示例中,通过在之后声明inline函数将外部可见性追溯到extern定义:可以在.c文件中的定义之后在.h文件中进行此声明,这使通常的用法成为现实。)

    如果内联几乎可以在任何地方完成,则不需要extern函数。但是,在诸如递归和引用函数地址的上下文中使用非内联调用。从某种意义上讲,您可以通过省略extern部分来获得“始终内联”的语义,但是对于任何简单的函数调用,这可能会任意失败,因为该标准并不仅仅因为没有其他选择而要求内联该调用。 (这是linked question的主题。)

    C++通过“模糊链接”的实现概念来解决这个问题。这个在标准中没有指定,但是在编译器内部是非常真实且棘手的。 C编译器应该比C++更容易编写;我相信这可以解释两种语言之间的差异。

    关于c - C99内联背后的想法是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23272985/

    10-13 08:51