C 避免由于在多个编译单元的情况下包含相同的头文件而导致多个定义

C 避免由于在多个编译单元的情况下包含相同的头文件而导致多个定义,c,header-files,multiple-definition-error,C,Header Files,Multiple Definition Error,我有一个常用函数f()。我希望f()位于头文件util.h,这样我就可以轻松地使用f(),而无需任何额外编译: user1.c: #include "util.h" int main(){ f(); return 0; } gcc -o user1 user1.c #include "util.h" void user2_function(){ f(); // do other jobs } #include "util.h" extern void

我有一个常用函数
f()
。我希望
f()
位于头文件
util.h
,这样我就可以轻松地使用
f()
,而无需任何额外编译:

user1.c

#include "util.h"
int main(){
    f();
    return 0;
}
gcc -o user1 user1.c
#include "util.h"

void user2_function(){
     f();
     // do other jobs
}
#include "util.h"
extern void user2_function();
int main(){
    f();
    user2_function();
    return 0;
}
util.h

void f(){
    // do some job
}
编译
user1.c

#include "util.h"
int main(){
    f();
    return 0;
}
gcc -o user1 user1.c
#include "util.h"

void user2_function(){
     f();
     // do other jobs
}
#include "util.h"
extern void user2_function();
int main(){
    f();
    user2_function();
    return 0;
}
当有两个编译单元
unit2.o
unit3.o
时,就会出现问题。其源代码如下:

gcc -c user2.c
gcc -c user3.c
gcc -o user user2.o user3.o
user2.c

#include "util.h"
int main(){
    f();
    return 0;
}
gcc -o user1 user1.c
#include "util.h"

void user2_function(){
     f();
     // do other jobs
}
#include "util.h"
extern void user2_function();
int main(){
    f();
    user2_function();
    return 0;
}
user3.c

#include "util.h"
int main(){
    f();
    return 0;
}
gcc -o user1 user1.c
#include "util.h"

void user2_function(){
     f();
     // do other jobs
}
#include "util.h"
extern void user2_function();
int main(){
    f();
    user2_function();
    return 0;
}
当我尝试编译这些源代码时,我得到了f的多个定义,如下所示:

gcc -c user2.c
gcc -c user3.c
gcc -o user user2.o user3.o
问题是如何解决多重定义问题?还是有更好的解决方案

在实际情况中,
util.h
中有数百个函数,大约有50个不同的编译单元

我试图避免使用库和实用程序函数的编译步骤,因为:

  • 我使用了很多不同的平台
  • 我想知道是否有一个简单的解决方案,即不使用
    cmake
  • 我还对协处理器使用交叉编译
  • 我希望编译实用程序函数时使用的标志与编译用户代码时使用的标志相同

  • 您实际上是在头文件中指定函数体。因此,目标代码将被发送到两个目标文件中,这是不允许/无效的

    要纠正这一点:

    • 将函数标记为
      inline
    • 在头文件中仅放置函数的正向声明,并在单独的源代码文件中指定主体,然后将其与其他源代码文件一起编译

    util.h
    更改为
    util.c

    并使用新的
    util.h
    ,其中包含

    void f(); 
    

    相反。

    如果要在多个文件中使用它,请在头文件中将其设置为静态,或者在头文件中声明它并在其自己的源文件中定义它。试图从标题中使用非静态函数定义……不会很好地工作。正如你所发现的,艰难的道路。在
    中没有定义诸如
    printf()
    之类的函数是有原因的;就是这样!在运行时性能、TLB未命中计数、指令缓存未命中计数等方面,使用
    静态
    静态内联
    是否有任何相反的效果。?编译时间对我来说并不重要。如果它是静态的,那么每个包含头的文件都会得到函数的一个副本,不管它是否被使用,因此程序最终会得到函数代码的多个副本。如果使用
    静态内联
    ,则仅当使用它时才会生成代码。因此,会浪费空间,而且如果大量使用,最终可能会需要内存中相同代码的多个副本,从中调用代码的每个文件都有一个副本,这增加了指令缓存未命中的可能性。使用多个文件向程序中添加一个额外的对象文件很容易。使用一个库使它更容易。我尽量避免
    您然后与其他源代码文件一起编译。我需要一个简单的解决方案,因为有很多平台,交叉编译,标记一致性,…声明函数
    static
    也可以,是的,尽管它会有不同的含义/效果。
    static
    函数实际上会在两个翻译单元中发出它的主体,但是编译器/链接器会使用魔法,这样实际上就不会有两个定义。也就是说,您将有两份该函数的副本。在
    inline
    的情况下,函数被发送到两个翻译单元中,但链接器随后删除其中一个定义。也就是说,您将只有一个函数副本。在标头中将函数定义为
    静态
    函数将起作用,但会在使用标头的每个对象文件中复制代码。此外,如果文件需要头而不是函数,则函数仍将被定义(但未使用,可能导致编译器警告)。如果函数足够小,使
    内联
    成为一个合理的选项,那么
    静态内联
    函数定义可能会工作得更好,尽管编译器不会在不合理的情况下内联它。声明函数
    内联
    与其大小无关。您没有重写编译器的内联逻辑。
    inline
    关键字的意思完全不同。