C/ c++ -条件头文件包含不工作



我的项目中有三个文件。

交流
公元前
test.h

test.h声明

namespace test_namespace {
    int i;
    void f1();
};

test.h也被

包围
#ifndef __x
#define __x
...
#endif

现在,a.c包括test.h, b.c也包括test.h。A.c有main()函数,b.c有test_namespace::f1()

的实现

但是,在编译时,我得到一个链接错误-

"test_namespace::i is already defined in <b.c's object file mapping in /tmp>"

如果我小心地在test.h中包含条件编译预处理器指令,为什么它被包含在a.c和b.c两个文件中?

同样值得注意的是,如果我将b.c单独编译为共享库,然后在链接a.c的目标文件时将其用作共享库,我不会得到此错误。

谁能解释一下上面的错误给我,特别是在面对条件编译指令?

不能在头文件中声明变量。符号test_namespace::i同时被a.c和b.c导出。链接器找到了这两个,但不知道该使用哪个。

你想在test.h中做的是:

namespace test_namespace {
    extern int i;
    void f1();
}

,然后在中声明test_namespace::i。

namespace test_namespace {
    int i;
}

条件包含用于防止为同一源文件而不是为整个项目包含两次头文件。假设您有标题a.hb.h,以及b.h #includea.h。然后,如果c.c需要从两个头的东西,它#include这两个。由于C预处理器使用文字文本替换,当它包含b.h时,现在文件中将有两个#include "a.h"指令,造成多个声明的混乱。(编辑:澄清你为什么在这种情况下遇到问题。)

Include守卫的作用是在编译单元的构建过程中保护多个包含。当您有两个单独的代码文件和一个头文件时,就像您的示例一样,它们不是必需的。

(因此,当test.c使用a.hb.h时,在b.h需要#包括a.h的情况下,请考虑更多)

但是这是一个关于include守卫约定的注释,以及它在这种情况下如何没有给你带来任何东西。您遇到的具体技术问题(正如其他人指出的那样)是,您基本上在两个不同的目标文件中定义了相同的变量,当链接器将所有内容拉到一起时,它不知道您是想要a.o还是b.o中的变量。

(注意:虽然编译器通常可以设置为覆盖的东西,并使用namespace这样的特性来构建c++代码,即使扩展名是.c -你可能应该使用其他东西,如.cpp: c++代码文件扩展名?

在header中定义test_namespace::i。你可能需要的是头中的extern int i;,并且定义在其中一个源文件。

当你说

int i;

实际上做了两件的事情:

1)声明符号i

2)在object文件

中为i保留一些空间和一个符号

技巧在于(1)应该只在每个文件中执行一次(实际上在这种情况下您可以重复它)——这就是为什么您有条件包含,您已经正确地完成了——但是(2)应该只在每个程序

中执行一次。

解决方案是让头文件做

// Only declare -- don't create a symbol
extern int i;

在*.c文件中执行

int i;

头守卫(#ifndef ..)#define . .#endif)正在正常工作。a.cb.c都包含test.h,因此它们都得到该头文件的副本。(当编译程序时,#include所做的是将头文件的内容复制粘贴到源文件中。)

因为它们都有头文件的副本,所以它们都定义了变量test_namespace::i。当链接器试图链接从a.c生成的代码和从b.c生成的代码时,它发现它们都定义了那个变量。它不知道该怎么做,所以它没有完成并输出一个错误。

最新更新