4

I have global variables that I define in the Utility namespace. This utility is included in several files and it looks like this:

#ifndef _UT_
#define _UT_
namespace UT {
  std::string PLATFORM_LINUX_NAME = "linux";
  std::string  PLATFORM_MACOSX_NAME = "macosx";
  std::string  PLATFORM_WINDOWS_NAME = "windows";
  #if defined(OS_WIN)
    int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
  #elif defined(OS_LINUX)
    int PLATFORM = PLATFORM_LINUX;
  #elif defined(OS_APPLE)
    int PLATFORM = PLATFORM_MACOSX;
  #endif
};

When I include this file in for example files A.h and B.h and C.h, I'm getting a compiler warning that says:

warning LNK4006: "int UT::PLATFORM" (?PLATFORM@UT@@3HA) already defined in A.obj; second definition ignored
warning LNK4006: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > UT::PLATFORM_LINUX_NAME" (?PLATFORM_LINUX_NAME@UT@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) already defined in A.obj; second definition ignored

What is the best way that does not involve creating a class for solving this? Or is creating a UT class the only way?

dda
  • 6,030
  • 2
  • 25
  • 34
user63898
  • 29,839
  • 85
  • 272
  • 514
  • You should be aware that identifiers beginning with an underscore followed by a capital letter, such as `_UT_`, are reserved for the compiler. See details in for example in this question: http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – Magnus Hoff Jul 02 '12 at 12:50
  • By the way, maybe you should also group them in an enum, just for clarity... – Mihai Todor Jul 02 '12 at 12:59

3 Answers3

10

Define the variables in a single .cpp file and declare them in the .h file. In UT.h:

namespace UT
{
    extern const std::string PLATFORM_LINUX_NAME;
    extern const std::string PLATFORM_MACOS_NAME;
    extern const std::string PLATFORM_WINDOWS_NAME;
    extern const int PLATFORM;
}

in UT.cpp:

namespace UT
{
    const std::string PLATFORM_LINUX_NAME   = "linux";
    const std::string PLATFORM_MACOS_NAME   = "macosx";
    const std::string PLATFORM_WINDOWS_NAME = "windows";

    #if defined(OS_WIN)
    const int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
    #elif defined(OS_LINUX)
    const int PLATFORM = PLATFORM_LINUX;
    #elif defined(OS_APPLE)
    const int PLATFORM = PLATFORM_MACOSX;
    #endif


}

I added const qualifier as these appear to be constant values.

hmjd
  • 120,187
  • 20
  • 207
  • 252
1

One solution is to make them all static, in which case each object file gets its own copy. Another possibility is to only put the declaration in the header and put the definitions in a separate file.

Antimony
  • 37,781
  • 10
  • 100
  • 107
0

Try

#ifndef _INCL_GUARD
#define _INCL_GUARD

std::string PLATFORM_LINUX_NAME     = "linux";
std::string  PLATFORM_MACOSX_NAME   = "macosx";
std::string  PLATFORM_WINDOWS_NAME  = "windows";



#if defined(OS_WIN)
    int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
#elif defined(OS_LINUX)
    int PLATFORM = PLATFORM_LINUX;
#elif defined(OS_APPLE)
    int PLATFORM = PLATFORM_MACOSX;
#endif

#endif
Jacob Seleznev
  • 8,013
  • 3
  • 24
  • 34
  • I think he would have gotten an exception anyway from the compiler if he didn't use the last #endif... – Mihai Todor Jul 02 '12 at 12:50
  • In VS 2010, intelliSense can spot it an the compiler provides a specific error: error C1070: mismatched #if/#endif pair in file 'test.h'. I was thinking that the compiler should do the same... I don't see a valid scenario where one would want / need to have an #if inside a file and the matching #endif inside another... – Mihai Todor Jul 02 '12 at 13:12