【问题标题】:#ifndef works only for "declaration" parts?#ifndef 仅适用于“声明”部分?
【发布时间】:2016-08-01 12:50:34
【问题描述】:

我有这样的 IGlobal.h 文件:

#ifndef _IGLOBALS_
#define _IGLOBALS_

#define _USE_MATH_DEFINES

#define PLUG_NUM_CHANNELS 2
#define PLUG_NUM_PRESETS 1
#define PLUG_FPS 100
#define PLUG_PPQ 96
#define KNOB_NUM_FRAMES 128
#define PIANOROLL_MIN_NOTES 2
#define PIANOROLL_MAX_NOTES 8
#define PIANOROLL_MIN_VELOCITY 40
#define PIANOROLL_MAX_VELOCITY 127
#define PIANOROLL_PATTERN_LENGTH PLUG_PPQ * 4
#define LFO_NUM_SAMPLES 882
#define WAVEPLAYER_WIDTH 441
#define WAVEPLAYER_HEIGHT 136
#define WAVEPLAYER_PATH_LENGTH 256
#define ENVELOPE_MIN_VALUE 0.0001

#include <algorithm>
#include <random>
#include <chrono>
#include <math.h>
#include <cmath>
#include "IPlug_include_in_plug_hdr.h"

using namespace std;

// bitmaps
IBitmap gBitmapKnobGeneral;

#endif // !_IGLOBALS_ 

我经常从项目中的 .h/.cpp 文件中包含它。 IBitmap 是一个结构体。

当我构建(编译)时,它说:

LNK1169 one or more multiply defined symbols found
LNK2005 "struct IBitmap gBitmapKnobGeneral" ?gBitmapKnobGeneral@@3UIBitmap@@A) already defined in ICustomControls.obj

事实上,我每次包含 IGlobal.h 时都会得到它。 #ifndef 不应该放弃这个问题吗?或者编译器自动只为declarations 而不是definitions

【问题讨论】:

  • #endif 在哪里?或者这只是文件的开头?请您添加整个错误消息吗? IPlug_include_in_plug_hdr.h 包含保护吗?顺便说一句,我认为#define PIANOROLL_PATTERN_LENGTH PLUG_PPQ * 4 可能会导致一些糟糕的预处理器问题。最好加上括号。
  • 一般来说,你会在头文件中声明一个变量为extern,然后在一个cpp文件中定义它。
  • @RetiredNinja:是的,通常!但是如果我不这样做,编译器会自动执行吗?
  • 为什么你有#include &lt;math.h&gt;,然后是#include &lt;cmath&gt;?检查Math constants

标签: c++ include-guards


【解决方案1】:

回答 #ifndef 适用于整个文件的问题。

问题是当你写 IBitmap gBitmapKnobGeneral;您将在每个包含标头的源文件中创建一个实例。 我假设您要做的是创建一个全局实例。 在这种情况下,你会想写。

  extern IBitmap gBitmapKnobGeneral;

在 IGlobal.h 文件中,然后在其中一个源文件中创建一个实例,例如 IGlobal.cpp 与

 IBitmap gBitmapKnobGeneral;

【讨论】:

  • 当然。但是由于有 ifndef,它不应该重新编译这个文件。相反,由于有“定义”,它确实如此。智能编译器?
  • 我想最好的说法是,对于您编译的每个源文件(单元),定义都被重置。因此,当您编译第二个源文件时,即使您有 ifndef,它也会创建一个名为 gBitmapKnobGeneral 的全局变量。然后,当链接器尝试合并从两个源文件创建的 obj 文件时,就会出现问题。
【解决方案2】:

在 C++ 中,头文件没有被编译,它们被“粘贴”到源 (cpp) 文件中。每个源文件都有自己独立的一组#defines - 如果你把它放到一个 cpp 文件中

#define A 1

这个变成另一个

#ifndef A
#error A is not defined
#endif

您收到错误“A 未定义”。在您的情况下,每个包含标头 IGlobal.h 的源文件都会通过您的标头一次(#ifdef 保护阻止它多次解析)并定义 IBitmap gBitmapKnobGeneral; 您的程序最终会得到变量的多个定义。要了解如何解决问题,请参阅其他答案和 cmets。

【讨论】:

  • "您的程序以变量的多个定义结束。"如果(如您所说)它包含一次标题,为什么会这样?不清楚。
【解决方案3】:

#ifndef 检查之前是否定义了标识符,如果没有,则它包含#ifndef 和对应的#endif/#else 之间的代码。 如果您之前定义了此标识符,那么代码在预处理后将不存在,因此我将检查问题是否不在包含的文件中或 IGlobal.h 中定义的符号中 - 可能是这些“常量”之一(例如 PLUG_NUM_CHANNELS)也在别处。

编辑: 看看#pragma once - 在我看来,它是更干净的解决方案,可以省去很多标识符的麻烦。

【讨论】:

  • 或者在定义包含保护之前使用#undef _IGLOBALS_
  • 也许,但我们不知道问题出在哪里——它可能在其他地方(也许是IPlug_include_in_plug_hdr.h)。话虽如此,我会将全局变量提取到单独的文件和命名空间中——我认为这将是更清洁的解决方案。
  • 不。它说LNK2005 "struct IBitmap gBitmapKnobGeneral" (?gBitmapKnobGeneral@@3UIBitmap@@A) already defined in ICustomControls.obj
  • 所以我认为你应该使用重写行 IBitmap gBitmapKnobGeneral;extern struct IBitmap gBitmapKnobGeneral;
  • 我知道!但为什么!? #ifndef 应该忽略它,因为它不再执行了
猜你喜欢
  • 2015-07-16
  • 2013-11-04
  • 2021-05-11
  • 2019-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
相关资源
最近更新 更多