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

How does the #ifndef deal with the globally declared variables and my own variables?

本文关键字:变量 声明 自己的 我自己 全局 何处理 处理 #ifndef      更新时间:2023-10-16

有一个问题让我很困惑。我知道这样做不对,但我不知道为什么。以及#ifndef#如何定义#endif。同谋者如何处理变量,如下面的"a"answers"b";

代码很简单:(myh.h(:

#ifndef P_H
#define P_H
struct P{
      int a;   
};
int b;
#endif

另一个文件s.cpp

#include"myh.h"
P a1;

主.cpp:

#include<iostream>
#include"myh.h"
using namespace std;
int main()
{
    P a2;
   return 0;
}  

错误是b的多重定义;正如我所知。我有两个问题:1.正如一些书所说,如果你使用#ifndef,编译器不会包含两次,那么为什么"b"似乎包含两次。

  1. "a"、"b"answers"P"有什么区别。为什么"a"answers"P"毫无疑问。我不知道我认为"P"是一个与"b"水平相同的变量是否正确?或者"P"只是类型的一个定义

如果它是局部和全局的区别,为什么"p"是对的?

我真的很困惑。请原谅你帮我。谢谢。

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

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

但是:由于cpp文件(连同包含的头文件(是单独处理的,
如果在不同的cpp文件中包含相同的头文件,则没有帮助。

Ie。您可以随心所欲地包含标题,但它们不应该包含变量。

关于你的第二个问题:p只是一个"描述"什么是"p"。
(每个P都有一个int a。但在那个时候,没有P。(。
b是一个实际的int,它可以容纳数字。。。

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

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

如何修复

  • 不要这样做。如果int b不需要是全局的,则不要将其粘贴在标头中
  • 在myh.h中,将其声明为extern int b。在main.cpp中,将其声明为int b这是一个常见的修复方法,但这意味着如果您更改b的类型,则需要在两个位置进行更改
  • 稍微复杂一点。在我的中

    #ifdef main_c
    #define EXTERN
    #else
    #define EXTERN extern
    #endif
    EXTERN int b;
    

    在main.cpp 中

    #define main_c
    #include "myh.h"
    

回答第二个问题,b是全局变量,p是局部变量。

标题保护分别适用于每个翻译单元。您至少有两个(s.cpp和main-cpp(。因此,"int b"是以这些翻译单位定义的。

还要注意,预处理器指令不会影响编译器,而是影响传递给编译器的经过预处理的文本。

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

顺便说一句:p实际上是不同的变量。正如你所说,一个是奈恩的本地人,另一个是s.cpp的全球人。

这里有一些东西可以帮助您"发现"问题:

首先,错误不是编译时错误,而是链接时错误。尝试:编译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中。Linker给出了这个错误。

要查看对象文件中的所有符号,可以使用nm命令。尝试:

nm s.o

也可以尝试:

nm main.o

两者都应包含一行:

00000000 B b

现在,为什么我们没有得到struct Pint a的错误?因为它们不是符号表的一部分。