1

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?

sepp2k
  • 363,768
  • 54
  • 674
  • 675
markzzz
  • 47,390
  • 120
  • 299
  • 507
  • 3
    Where's the `#endif`? Or is that just the beginning of the file? And could you add the whole error message, please? Is `IPlug_include_in_plug_hdr.h` include-guarded? BTW, I think `#define PIANOROLL_PATTERN_LENGTH PLUG_PPQ * 4` might incur some bad preprocessor problems. Better add parantheses. – cadaniluk Aug 01 '16 at 12:52
  • 2
    In general you would declare a variable in a header as extern and then define it in one cpp file. – Retired Ninja Aug 01 '16 at 12:57
  • @RetiredNinja: yes, usually! But if I don't do it, compiler does it automatically? – markzzz Aug 01 '16 at 13:07
  • Why do you have `#include ` and then `#include `? Check [Math constants](https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx) – Anto Jurković Aug 01 '16 at 13:09
  • http://stackoverflow.com/questions/8020113/c-include-guards – Retired Ninja Aug 01 '16 at 13:24
  • [How do I use extern to share variables between source files in C?](http://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files-in-c) – Anto Jurković Aug 01 '16 at 14:13

3 Answers3

2

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;
Kennet
  • 323
  • 4
  • 12
  • Of course. But since there's ifndef, it shouldn't re-compile this file. Instead, since there's "definition", it does. Smart compiler? – markzzz Aug 01 '16 at 13:14
  • I guess the best way to put it is that for each source file (unit) you compile the defines are reset. So when you compile the second source file it also creates a global variable called gBitmapKnobGeneral even though you have a ifndef. Then when the linker tries to merge the obj files created from the two source files this creates the problem. – Kennet Aug 01 '16 at 13:22
0

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.

Marian Spanik
  • 1,079
  • 1
  • 12
  • 18
  • "Your program ends up with multiple definitions of the variable." Why this if (as you said) it includes header once? That's not clear. – markzzz Aug 01 '16 at 16:58
-1

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

pocza
  • 632
  • 6
  • 10
  • Or just use `#undef _IGLOBALS_` prior to defining the include guard. – cadaniluk Aug 01 '16 at 13:00
  • Maybe, but we don't know where the problem is - it might be somewhere else (maybe `IPlug_include_in_plug_hdr.h`). That being said, I would extract globals to a separate file and namespace - it would be cleaner solution in my opinion. – pocza Aug 01 '16 at 13:06
  • Nope. It says `LNK2005 "struct IBitmap gBitmapKnobGeneral" (?gBitmapKnobGeneral@@3UIBitmap@@A) already defined in ICustomControls.obj ` – markzzz Aug 01 '16 at 13:09
  • So I think you should use rewrite line `IBitmap gBitmapKnobGeneral;` to `extern struct IBitmap gBitmapKnobGeneral;` – pocza Aug 01 '16 at 13:18
  • I know! But WHY!? #ifndef should ignore it, because its not executed anymore – markzzz Aug 01 '16 at 14:04
  • I think if I would see your source code, it would be much simpler. If you haven't come up with solution yet, I can only suggest compiling with -E option (if your filling lucky - it will output preprocessed file, but that's a little bit messy) or using `grep`/`ack` to seek `IBitmap gBitmapKnobGeneral;` - it will find another definition of your object in a different file. – pocza Aug 02 '16 at 07:15