#ifndef如何处理全局声明的变量和我自己的变量?

时间:2014-03-29 09:36:53

标签: c++

有一个问题让我感到困惑。我知道这样做是不对的,但我不知道为什么。 #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;似乎被包括两次。

  1. &#34; a&#34;的差异是什么? ,&#34; b&#34;和&#34; P&#34;。为什么&#34; a&#34;和&#34; P&#34;毫无疑问。我不知道我是否正确考虑&#34; P&#34;作为变量与&#34; b&#34;相同的变量?或者&#34; P&#34;只是类型的定义。
  2. 如果是本地和全球的差异,为什么&#34; P&#34;正确?

    我真的很困惑。 Pardern你的时间来帮助我。谢谢。

4 个答案:

答案 0 :(得分:1)

标题保护分别适用于每个翻译单元。你至少有两个(s.cpp和主cpp)。因此,&#39; int b`在这些翻译单元中定义。

另请注意,预处理程序指令不会影响编译器,但会将预处理的文本传递给编译器。

将您的变量声明为extern int b,并在(可能)s.cpp中包含int b;

Btw:P&#39实际上是不同的变量。正如你所说,一个是本地的nain,另一个是s.cpp中的全局,只有。

答案 1 :(得分:1)

首先,关于汇编:
您必须了解编译器将首先单独编译每个cpp文件 (在链接过程中他们一起在可执行文件中之前)

如果你有一个文件main.cpp和两次#include <abc.h>,那么 您可以阻止第二个包含在#ifndef - 使用中出错 如果您的main.cpp包含a.hb.h,但a.h也包含b.h#ifndef等也会有所帮助。

但是:由于cpp文件(连同包含的标题)分别处理,
如果在不同的cpp文件中包含相同的头文件,它将无济于事。

IE中。您可以根据需要包含标题,但它们不应包含变量。

关于你的第二个问题:P只是一个“描述”应该是什么“P” (每个P都有int a。但那时,没有P.) b是一个可以保存数字的实际int ...

答案 2 :(得分:0)

这是一个非常常见的问题 - 它可以在一些链接器(不是编译器)上工作,但不能在其他链接器上工作(正如您所发现的那样)。

问题是在标题中声明了 int b ,这意味着它在包含myh.h的每个文件中被声明为全局可见。包含警卫将保护您不会在同一个文件中多次定义相同的内容,但它不会保护您不会在不同的文件中多次定义它。

如何修复

  • 不要这样做。如果 int b 不需要是全局的,请不要将其粘贴在标题
  • 在myh.h中将其声明为 extern int b; 。在main.cpp中,将其声明为 int b; 这是一个常见修复,但这意味着如果更改b的类型,则需要在2个位置进行更改
  • 更详细一点。在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 Pint a内部收到错误消息?因为它们不是符号表的一部分。