简体   繁体   English

C/C++ - 有条件的 header 文件包含不起作用

[英]C/C++ - Conditional header file inclusion not working

I have three files in my project.我的项目中有三个文件。

a.c a.c
b.c b.c
test.h测试.h

test.h declares a test.h 声明一个

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

test.h is also surrounded by test.h 也被包围

#ifndef __x
#define __x
...
#endif

now, a.c includes test.h and b.c also includes test.hac has the main() function, and b.c has the implementation of test_namespace::f1() now, a.c includes test.h and b.c also includes test.hac has the main() function, and b.c has the implementation of test_namespace::f1()

However, on compiling this, I get a linking error -但是,在编译这个时,我得到一个链接错误 -

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

If I've taken care to include conditional compilation preprocessor directives in test.h, why is it being included in both files a.c and b.c?如果我注意在 test.h 中包含条件编译预处理器指令,为什么它会包含在 a.c 和 b.c 两个文件中?

Also is noteworthy that if I compile b.c separately as a shared library and then use it as a shared library while linking ac's object file, i don't get this error.另外值得注意的是,如果我将 b.c 单独编译为共享库,然后在链接 ac 的 object 文件时将其用作共享库,则不会出现此错误。

Can someone please explain the above error to me, specially in the face of the conditional compilation directives?有人可以向我解释上述错误,特别是面对条件编译指令吗?

You cannot declare variables inside a headerfile.您不能在头文件中声明变量。 The symbol test_namespace::i becomes exported by both a.c and b.c.符号 test_namespace::i 由 a.c 和 b.c 导出。 The linker find's both and doesn't know which one to use. linker 找到了两者,但不知道使用哪一个。

What you want to do in test.h is:你想在 test.h 中做的是:

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

and then declare test_namespace::i in eather a.c or b.c:然后在a.c或 b.c 中声明 test_namespace::i:

namespace test_namespace {
    int i;
}

Conditional inclusion is used to prevent headers from being included twice for the same source file not for the whole project.条件包含用于防止标题被两次包含在同一个源文件而不是整个项目中。 Suppose you have headers ah and bh , and bh #include s ah .假设您有标题ahbh以及bh #include s ah Then if c.c needs things from both headers, it #include both of them.然后,如果c.c需要来自两个标题的东西,它#include他们两个。 Since the C preprocessor using literal text substitution, when it includes bh , there will now be two #include "ah" directives in your file, wreaking the havoc of multiple declarations.由于 C 预处理器使用文字文本替换,当它包含bh时,您的文件中现在将有两个#include "ah"指令,对多个声明造成严重破坏。 (Edit: clarify why you run into problems in this case.) (编辑:澄清为什么在这种情况下会遇到问题。)

Include guards are there to protect multiple header inclusions in the build of a compilation unit.在编译单元的构建中,包括防护装置可以保护多个header包含。 They aren't necessary for cases when you have two separate code files and one header, like your example.当您有两个单独的代码文件和一个 header 时,它们不是必需的,例如您的示例。

(So think more when test.c uses ah and bh , in those cases where bh needs to #include ah .) (所以在test.c使用ahbh时要多考虑,在bh需要#include ah的情况下。)

But that's a note about what the include guard convention does and how it isn't buying you anything in this case.但这是关于包含守卫约定的作用以及在这种情况下它如何不为您购买任何东西的说明。 The specific technical issue you hit (as others have pointed out) is that you're basically defining the same variable in two different object files, and when the linker goes to pull everything together it doesn't know if you want the variable from ao or bo .您遇到的具体技术问题(正如其他人指出的那样)是您基本上在两个不同的 object 文件中定义了相同的变量,并且当 linker 将所有内容放在一起时,它不知道您是否想要来自ao的变量或bo

( Note: While compilers can generally be set to override things and build C++ code using features like namespace even if the extension is .c - you probably should be using something else, like .cpp : C++ code file extension? .cc vs.cpp ) ( Note: While compilers can generally be set to override things and build C++ code using features like namespace even if the extension is .c - you probably should be using something else, like .cpp : C++ code file extension? .cc vs.cpp )

You're defining test_namespace::i in the header.您在 header 中定义test_namespace::i What you probably want is extern int i;你可能想要的是extern int i; in the header, and a definition in one of the source files.在 header 中,以及其中一个源文件中的定义。

What's happening is that when you say发生的事情是当你说

int i;

this actually does two things:这实际上做了两件事:

1) Declares the symbol i 1) 声明符号i

2) Reserves some space and a symbol for i in the object file 2) 在 object 文件中为i保留一些空间和符号

The trick is that (1) should only be done once per file (actually you can repeat it in this case) -- which is why you have the conditional include, which you have done correctly -- but (2) should only be done once per program诀窍是(1)每个文件只应该执行一次(实际上你可以在这种情况下重复它)——这就是你有条件包含的原因,你已经正确地完成了——但是(2)应该只完成每个程序一次

The solution is to have the header do解决方案是让 header 做

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

And in the *.c file do在 *.c 文件中做

int i;

The header guards ( #ifndef .. #define .. #endif ) are working as they should. header 防护装置 ( #ifndef .. #define .. #endif ) 正在正常工作。 Both a.c and b.c include test.h , so they both get a copy of that header. a.cb.c都包含test.h ,因此它们都获得了 header 的副本。 (When you compile a program, what #include does is to literally copy-paste the contents of the header inside the source file.) (当你编译一个程序时, #include所做的就是将 header 的内容复制粘贴到源文件中。)

Since they both have a copy of the header, they both define the variable test_namespace::i .由于它们都有 header 的副本,因此它们都定义了变量test_namespace::i When the linker tries to link the code generated from a.c with the code generated from b.c it finds that they both define that variable.当 linker 尝试将从a.c 生成的代码与从 b.c生成的代码链接时,它发现它们都定义了该变量。 It doesn't know what to do, so it doesn't complete and outputs an error.它不知道该怎么做,所以它没有完成并输出错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM