3

I have declared some constant variable in seperate header (i.e., constant.h).

I include the constant.h in my debug.cpp as to access the variable.

I include the constant.h, debug.h in my main.cpp as to access the variable.

When I compile, the error it shows **multiple definition** of **IF_DEBUG_ENABLED**.

Kindly tell me what is actually I'm doing wrong. Also, please note that this is my first day on my very first c/c++ application. I've never even read it in school.

My code source is as follows: as

/-- constant.h --/

#ifndef CONSTANT_H
#define CONSTANT_H

const char* APP_NAME            = "ymcmcb";
const bool  IF_DEBUG_ENABLED    = true;

#endif // CONSTANT_H

/-- debug.h --/

#ifndef DEBUG_H
#define DEBUG_H

#include <QString>

class Debug
{  
public:
    static void Log(QString Message);
};

#endif // DEBUG_H

/-- debug.cpp --/

#include "constant.h"
#include "debug.h"

#include "QDebug"

static void Log(QString Message)
{
    if (IF_DEBUG_ENABLED)
        qDebug() << Message;    //It says problem is here
}

/-- main.cpp --/

#include "constant.h"
#include "debug.h"

int main(int argc, char *argv[])
{
    Debug::Log("New application has been run");
}
paulsm4
  • 114,292
  • 17
  • 138
  • 190
VPZ
  • 741
  • 8
  • 19
  • I don't get the same linker error as you: I get `multiple definition of 'APP_NAME'` (not of `'IF_DEBUG_ENABLED'`). I also get a second error: `undefined reference to 'Debug::Log(QString)'`. – gx_ Sep 02 '13 at 19:49
  • Since you're starting out you have plenty to learn. For a little while at least I'd stick to programs in a single source file. One less thing to trip you up. – john Sep 02 '13 at 19:58
  • One other thing. There's no such language as C/C++, there's C and there's C++. You're learning C++. People who say C/C++ tend to get flamed. – john Sep 02 '13 at 20:00
  • One more thing, nicely asked question. Everything needed to answer it included. Much higher quality than we normally see on this forum. You'll go far. – john Sep 02 '13 at 20:02

2 Answers2

4

You should put the definition in a .cpp file, not in a header. In the header you should only put declarations : extern const bool IF_DEBUG_ENABLED; This will tell any code #includeing it that there exist some global variable named IF_DEBUG_ENABLED. Inside debug.cpp you should put the actual definition.

The guards only help to prevent you from defining multiple times in a single compilation unit. But you have two compilation units: debug.cpp (plus headers) and main.cpp (plus headers). which means you have multiple definitions of the variables in the header.


You have another problem: you implement a static function Log() but you should implement a static class-method Debug::Log().

Elazar
  • 20,415
  • 4
  • 46
  • 67
4

C and C++ have the concept of a "compilation unit", which is essentially "all the code in the file you tell me to compile plus all the files it includes".

The original pipeline for C compilation was to first run the "pre-processor" to read in all of the code, process the macros and defines etc, and output the resulting code into a single file (from memory, a .i file for intermediate)

foo.cpp

#include "foo1.h"
FOO {
    #include "foo2.h"
}

foo1.h

extern "C" int puts(const char*);
#define FOO int main()

foo2.h

puts("Hello, world\n");

Compile with g++ -Wall -E -o foo.i foo.cpp and g++ -Wall -o foo.exe foo.i

The foo.i file looks like this:

# 1 "foo.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "foo.cpp"
# 1 "foo1.h" 1
extern "C" int puts(const char*);
# 2 "foo.cpp" 2

int main() {
# 1 "foo2.h" 1
 puts("Hello, world!\n");
# 5 "foo.cpp" 2
}

This is a compilation unit. The process is simplified these days, the pre-processor being built in to the compiler itself, but the notion of a compilation unit still remains.

The problem with your code is that you are defining - not just declaring - IF_DEBUG_ENABLED in a header file, and thus potentially in multiple compilation units. When the linker tries to combine the compiled units into an executable, it's finding multiple instances of a variable with the same name. The linker has no way to tell that they were supposed to be the same thing.

To create a global variable or function visible between multiple compilation units (source files), you need a header declaration/prototype and a source-file definition/instance.

header

extern bool IF_DEBUG_ENABLED; // variable declaration.
extern void herp();           // function prototype, but
void herp();                  // the extern is optional for functions.

To be able to use either of these, you now need to back them up with a implementation.

source file

bool IF_DEBUG_ENABLED = true;

This is, assuming that you want it to be a run-time variable. Another option you have is to use a #define, just like the guard you were using:

constant.h

#ifndef CONSTANT_H // poor choice, there may be a CONSTANT_H somewhere else.
#define CONSTANT_H 1

...
#define IF_DEBUG_ENABLED // comment out to disable

#endif

source:

#if defined(IF_DEBUG_ENABLED)
   qDebug() << message;
#endif

This option doesn't allow you to change IF_DEBUG_ENABLED during run-time, the "qDebug() << message" code is only written to the executable if IF_DEBUG_ENABLED is defined at compile time.

Lastly, instead of using the #if ... #define ... #endif guard method, you can replace all three with a single line at the start of the file:

constant.h:

#pragma once  //<<-- compiler implements a guard for you.

#include <QString>

class Debug
{  
public:
    static void Log(QString Message);
};
kfsone
  • 23,617
  • 2
  • 42
  • 74
  • This way I am getting a undefined reference to "IF_DEBUG_ENABLED" when trying to assign value to the extern declared variable in my app's main (entry-point) function. – VPZ Sep 03 '13 at 03:07
  • Okay the thing is compiling but I'm confused on where to initialize those extern vars? – VPZ Sep 03 '13 at 03:15
  • Yo! I got the thing built up & running! Yours helped me in real. Clear as a mirror! :P (y) Thanks! – VPZ Sep 03 '13 at 03:21