【问题标题】:How to declare an inline function in C99 multi-file project?如何在 C99 多文件项目中声明内联函数?
【发布时间】:2011-07-10 21:40:57
【问题描述】:

我想在项目中定义一个内联函数,用c99编译。我该怎么做? 当我在头文件中声明函数并在 .c 文件中提供详细信息时,其他文件无法识别该定义。当我将显式函数放在头文件中时,我遇到了问题,因为使用它的所有 .o 文件都有定义的副本,因此链接器给了我一个“多重定义”错误。

我想做的是这样的:

header.h
inline void func()
{
    do things...
}


lib1.c
#include "header.h"
...

lib2.c
#include "header.h"

使用同时使用 lib1.o 和 lib2.o 的实用程序

【问题讨论】:

    标签: c linker c99 inline-functions


    【解决方案1】:

    很遗憾,并非所有编译器都完全符合 C99,即使他们声称会这样做。

    一种符合要求的方法是

    // header file. an inline definition alone is
    // not supposed to generate an external symbol
    inline void toto(void) {
      // do something
    }
    
    // in one .c file, force the creation of an
    // external symbol
    extern inline void toto(void);
    

    例如,较新版本的 gcc 可以正常工作。

    你可以通过定义类似的东西来为其他编译器(伪装者)摆脱它

    #ifdef PRETENDER
    # define inlDec static
    # define inlIns static
    #else
    # define inlDec 
    # define inlIns extern
    #endif
    // header file. an inline declaration alone is
    // not supposed to generate an external symbol
    inlDec inline void toto(void) {
      // do something
    }
    
    // in one .c file, force the creation of an
    // external symbol
    inlIns inline void toto(void);
    

    编辑:

    我知道的支持 C99 的编译器(通常是选项 -std=c99

    • gcc(版本 >= 4.3 IIRC)实现 正确的inline 模型
    • pcc 也是正确的
    • ggc
    • icc 只是在每个单元中发出符号 如果你不特别注意。但 这些符号是“弱”符号,所以 它们不会产生冲突。他们 只是炸毁你的代码。
    • opencc,AFAIR,遵循旧的 gcc 特定模型
    • clang 根本不会为 inline 函数发出符号,除非你有一个 extern 声明并且你在一个编译单元中使用函数指针。
    • tcc 只是忽略了inline 关键字

    【讨论】:

    • 多个定义可能源于在头文件中有函数的extern 声明。这将强制每个翻译单元发出函数的副本。
    • @Lindydancer:当然。但我要说的是,即使您只有 inline 声明,一些编译器也会生成符号。我将添加一些关于特定编译器的更多评论。
    • 谢谢詹斯。它有效(gcc 4.4.5 带有标志 std=gnu99 和 std=c99)。
    • @JensGustedt,与在所有情况下都在头文件中简单地使用 static inline 相比,以“新方式”执行此操作有什么好处吗?
    • @Mike,是的,在我的 POV 中有两个。首先,如果编译器决定不内联,则不要用函数的副本破坏可执行文件。然后,该函数可通过其地址唯一标识,所有指向它的指针将比较相等,即使它们源自不同的编译单元。顺便说一句,只是声明它staticstatic inline 完全相同,inline 几乎没有用处。现代编译器不会自行决定是否内联,程序员在优化方面是出了名的糟糕。
    【解决方案2】:

    如果单独使用,在 C99 中 inline 要求该函数定义在与使用它相同的翻译单元中(因此,如果您在 lib1.c 中使用它,则必须在 lib1.c 中定义它)。

    您还可以将方法声明为static inline(并将定义放在两个源文件之间共享的头文件中)。这避免了多定义问题,并让编译器在使用它的所有翻译单元中内联文件(如果您只在一个翻译单元中声明函数,它可能会也可能无法做到)。

    见:http://www.greenend.org.uk/rjk/2003/03/inline.html

    【讨论】:

    • 术语“翻译单元”包括源文件 (lib1.c) 和包含的所有头文件。这意味着应该可以将其放在header.h 中。要么编译器坏了,要么函数被声明为extern,这将解释这一点。
    【解决方案3】:

    我觉得你在头文件中定义和声明函数的时候不需要使用inline这个词,编译器通常默认把它当作inline,除非它太长,这样就足够聪明了将其视为正常功能。

    我认为多重定义可能是由于 Header 文件中缺少 Include Guard 造成的。

    你应该在标题中使用这样的东西:

    #ifndef HEADERNAME_H
    #define HEADERNAME_H
    
    void func()
    {
        // do things...
    }
    
    #endif
    

    【讨论】:

    • 有趣的是 - 标题 由#ifndef 保护。但我认为它没有工作,因为编译器仍然将标题放在每个 .o 文件中。
    猜你喜欢
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多