有一个问题让我感到困惑。我知道这样做是不对的,但我不知道为什么。 #ifndef #define #endif是如何工作的。编译器如何处理变量如下所示" a"和" b" ;
代码很简单:(myh.h):
#ifndef P_H
#define P_H
struct P{
int a;
};
int b;
#endif
另一个文件s.cpp
#include"myh.h"
P a1;
main.cpp:
#include<iostream>
#include"myh.h"
using namespace std;
int main()
{
P a2;
return 0;
}
错误是b的多重定义;就像我所知道的那样。我有两个问题:1。有些书说,如果你使用#ifndef,编译器不会包含两次,那么为什么&#34; b&#34;似乎被包括两次。
如果是本地和全球的差异,为什么&#34; P&#34;正确?
我真的很困惑。 Pardern你的时间来帮助我。谢谢。
答案 0 :(得分:1)
标题保护分别适用于每个翻译单元。你至少有两个(s.cpp和主cpp)。因此,&#39; int b`在这些翻译单元中定义。
另请注意,预处理程序指令不会影响编译器,但会将预处理的文本传递给编译器。
将您的变量声明为extern int b
,并在(可能)s.cpp中包含int b
;
答案 1 :(得分:1)
首先,关于汇编:
您必须了解编译器将首先单独编译每个cpp文件
(在链接过程中他们一起在可执行文件中之前)
如果你有一个文件main.cpp和两次#include <abc.h>
,那么
您可以阻止第二个包含在#ifndef
- 使用中出错
如果您的main.cpp包含a.h
和b.h
,但a.h
也包含b.h
,
#ifndef
等也会有所帮助。
但是:由于cpp文件(连同包含的标题)分别处理,
如果在不同的cpp文件中包含相同的头文件,它将无济于事。
IE中。您可以根据需要包含标题,但它们不应包含变量。
关于你的第二个问题:P只是一个“描述”应该是什么“P”
(每个P都有int a
。但那时,没有P.)
b是一个可以保存数字的实际int ...
答案 2 :(得分:0)
这是一个非常常见的问题 - 它可以在一些链接器(不是编译器)上工作,但不能在其他链接器上工作(正如您所发现的那样)。
问题是在标题中声明了 int b ,这意味着它在包含myh.h的每个文件中被声明为全局可见。包含警卫将保护您不会在同一个文件中多次定义相同的内容,但它不会保护您不会在不同的文件中多次定义它。
如何修复
更详细一点。在myh.h中
#ifdef main_c
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int b;
在main.cpp
中#define main_c
#include "myh.h"
要回答第二个问题,b是全局变量,P是局部变量。
答案 3 :(得分:0)
这里的东西可以帮助你看到&#39;问题:
首先,错误不是编译时错误,而是链接时错误。尝试: 编译s.cpp:
g++ -c s.cpp
这应该编译好。由于s.cpp具有#include "myh.h"
,因此b的定义将出现在s.o
编译main.cpp
g++ -c main.cpp
这也应该编译好。由于main.cpp有#include "myh.h"
,因此b的定义将出现在main.o
现在尝试链接两个.o文件。简单的方法是:
g++ s.o main.o
这应该会给你关于b的多个定义的错误。原因是符号b存在于s.o和main.o中。链接器给出了这个错误。
要查看目标文件中存在的所有符号,可以使用nm
命令。尝试:
nm s.o
还可以尝试:
nm main.o
两者都应包含一行:
00000000 B b
现在,为什么我们不会在struct P
或int a
内部收到错误消息?因为它们不是符号表的一部分。