markzzz
markzzz

Reputation: 47945

#ifndef works only for "declaration" parts?

I have such as this IGlobal.h file:

#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_ 

which I include often from .h/.cpp file within the project. IBitmap is a struct.

When I Build (compile), it says:

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

And in fact I have it for each time I include IGlobal.h. Shouldn't #ifndef discard this problem? Or compiler automatically does it only for declarations and not definitions?

Upvotes: 1

Views: 132

Answers (3)

Marian Spanik
Marian Spanik

Reputation: 1109

In C++ header files are not compiled, they are "pasted" into source (cpp) files. Each source file maintains its own independent set of #defines - if you put this into one cpp file

#define A 1

and this into another one

#ifndef A
#error A is not defined
#endif

you get the error "A is not defined". In your case each source file which includes the header IGlobal.h gets through your header once (the #ifdef guard prevents it from parsing multiple times) and defines the IBitmap gBitmapKnobGeneral; Your program ends up with multiple definitions of the variable. To see how to fix the problem see other answers and comments.

Upvotes: 0

Kennet
Kennet

Reputation: 353

To answer the question #ifndef works for the entire file.

The problem is that When you write IBitmap gBitmapKnobGeneral; you will create an instance in every source file that includes the header. I assume that what you are trying to do is create a single global instance. In that case you would want to write.

  extern IBitmap gBitmapKnobGeneral;

in the IGlobal.h file and then create an instance in one of you source files for instance IGlobal.cpp with

 IBitmap gBitmapKnobGeneral;

Upvotes: 2

pocza
pocza

Reputation: 710

#ifndef checks whether identifier was defined previously, if not then it includes the code between #ifndef and corresponding #endif/#else. If you defined this identifier earlier, then the code won't be there after preprocessing, so I would check if problem isn't somewhere in files included or symbols defined in IGlobal.h - maybe one of those "constants" (e.g. PLUG_NUM_CHANNELS) is also somewhere else.

EDIT: look at #pragma once - it is in my opinion cleaner solution which saves a lot of trouble with identifiers.

Upvotes: -1

Related Questions