C99内联的理念是什么?

zsh*_*zsh 9 c c99 extern inline-functions

inline在C99 感到困惑.

这就是我想要的:

  1. 我希望我的函数在任何地方都被内联,而不仅仅局限于一个翻译单元(或一个编译单元,一个.c文件).
  2. 我希望函数的地址一致.如果我在函数指针中保存函数的地址,我希望函数可以从指针调用,我不希望在不同的翻译单元中重复相同的函数(基本上,我的意思是没有static inline).

C++就是inline这样做的.

但是(如果我错了请纠正我)在C99中没有办法得到这种行为.

我可以使用static inline,但它会导致重复(不同翻译单元中相同功能的地址不一样).我不希望这种重复.

所以,这是我的问题:

  1. inlineC99的理念是什么?
  2. 这个设计对C++的方法有什么好处?

参考文献:

  1. 这是一个高度评价C99的链接inline,但我不明白为什么.这只"仅在一个编译单元中"限制真的那么好吗?
    http://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/
  2. 这是C99的基本原理inline.我读过它,但我不明白.
    没有"静态"或"外部"的"内联"在C99中是否有用?
  3. 一篇不错的文章,提供了使用inline函数的策略.
    http://www.greenend.org.uk/rjk/tech/inline.html

答案摘要

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

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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

与编译:gcc -O3 main.c src.c -std=c99
检查装配有:gcc -O3 -S main.c src.c -std=c99,你会发现,my_max在两个内联call_and_print_addr()main().

实际上,这与参考文献1和参考文献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);
Run Code Online (Sandbox Code Playgroud)

在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"
Run Code Online (Sandbox Code Playgroud)

如果你剪切extern inline int my_max(int x, int y);并粘贴它main.c,你会发现这些汇编代码main.s.

因此,通过extern inline,您可以告诉编译器my_max()将定义和编译真实函数,您可以通过其地址调用它.

现在回顾一下C++,我们无法指定它.我们永远不会知道my_max()将在哪里,这是@Potatoswatter的"模糊联系".

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

Pot*_*ter 6

要获得类似C++的行为,您需要为每个TU提供可能内联调用的inline定义,并为一个TU提供外部可见的定义.这正是C标准的相关章节(函数说明符)中的示例1所示.(在该示例中,外部可见性inline通过以后声明函数来追溯应用于定义extern:此声明可以在.c文件中的定义之后在.h文件中完成,这将改变其常用用法.)

如果内联可以在任何地方完成,你就不需要这个extern功能.但是,在递归和引用函数地址等上下文中使用非内联调用.在某种意义上,您可以通过省略extern部分来获得"始终内联"语义,但是对于任何简单的函数调用,这可能会随意失败,因为标准并不要求仅仅因为没有替代方案而内联调用.(这是相关问题的主题.)

C++使用"模糊链接"的实现概念来处理这个问题; 这在标准中没有规定,但在编译器中是非常真实的,也很棘手.C编译器应该比C++更容易编写; 我相信这解释了语言之间的差异.