在链接两个对象文件时,使用#ifndef防止定义一个函数两次

Do #ifndef prevent defining a function twice when linking two object file?

本文关键字:定义 一个 两次 函数 对象 两个 链接 文件 使用 #ifndef      更新时间:2023-10-16

我有两个类实现(.cpp files)

它们都需要一个在header (.h)文件中实现的函数。两个.cpp文件都包含.h文件。编译完成后,两个.cpp文件变成两个.o文件。

在连接两个目标文件时是否定义函数两次?

#ifndef可以防止这种情况吗?

我使用#ifndef,但我得到以下消息,

ld: 1 duplicate symbol for architecture x86_64

您必须理解函数声明(具有给定名称和签名的函数存在的声明)和函数定义(决定函数实际做什么的代码)之间的区别。

如果在头文件中定义函数,则该函数将在每个object文件中定义,并且当您试图将它们链接在一起时将会发生冲突;#ifndef不能解决这个问题。

如果在头文件中声明函数,而在源文件中定义函数(源文件必须被编译成对象,并与使用它的对象链接),则不会出现这样的问题。在这个简单的例子中,不需要#ifndef

例如,函数foo可以在foo.h中声明:

int foo(int);

并在foo.cpp中定义:

int foo(int n)
{
  return(n+3);
}

#ifndef宏解决了一个不同的问题

作为Beta答案的替代方案,您可以通过使用inline关键字在头文件中定义一个自由函数,该函数将包含在多个翻译单元中。想想看:

// Foo.h
int foo(){return 1;}
// UsesFoo1.cpp
#include "Foo.h"
int usesFoo2(){return foo();}
// UsesFoo2.cpp
#include "Foo.h"
int usesFoo1(){return foo();}
// Main.cpp
#include <iostream>
int usesFoo1();
int usesFoo2();
int main()
{
   std::cout << usesFoo1() + usesFoo2() << std::endl;
}

这会产生一个链接器错误,因为int foo()是在两个独立的翻译单元中定义的。但是,如果您在这里添加inline关键字,则不会产生错误:

// Foo.h
inline int foo(){return 1;}

注意:在类定义内部定义的函数隐式地具有inline关键字,因此您可以省略它。