Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error LNK1169 on global const char*

I am experiencing some strange behavior with Visual Studio 2010 and C++. I have a header file in which I declare some global constants

#ifndef CONSTANTS_H
#define CONSTANTS_H

#define WIN32_LEAN_AND_MEAN

// Macros...
#define SAFE_RELEASE(ptr) { if (ptr) { ptr->Release(); ptr = NULL } }
#define SAFE_DELETE(ptr) { if (ptr) { delete ptr; ptr = NULL; } }

// Constants...
const char* CLASS_NAME = "WinMain";
const char GAME_TITLE[] = "DirectX Window";

const int GAME_WIDTH = 640;
const int GAME_HEIGHT = 480;

#endif

My problem comes in with the following line:

const char* CLASS_NAME = "WinMain";

When it's like this, and I build my solution I get the following 2 errors:

error LNK1169: one or more multiply defined symbols found, and

error LNK2005: "char const * const CLASS_NAME" (?CLASS_NAME@@3PBDB) already defined in graphics.obj

Now is strange since a ran a 'find in files' and I definitely do not declare it somewhere else ie no duplicate declarations.

Should I change it to:

const char* const CLASS_NAME = "WinMain";

OR

const char CLASS_NAME[] = "WinMain";

It compiles just fine! But as far as I know char* x is equivalent to char x[], and the fact that I'm enforcing 'const-ness' on both the pointer and the pointed-to value should make no difference.... or does it?

I'm a bit new to C++ development on the Windows platform, so any help will be greatly appreciated!

like image 431
mnemonic Avatar asked Dec 07 '12 22:12

mnemonic


3 Answers

You mistake is that you did not declare your constants as constants. In C++ syntax (as well as in C) in order to declare a constant pointer you have to do this

const char* const CLASS_NAME = "WinMain";

Note that your GAME_TITLE, GAME_WIDTH and GAME_HEIGHT are correctly declared as constants, which is why they give you no trouble. Only the CLASS_NAME is declared incorrectly, i.e. as non-constant.

Constants in C++ have internal linkage by default, which is why you can define them in header files without violating the One Definition Rule.

like image 53
AnT Avatar answered Oct 05 '22 22:10

AnT


Don't define variables in headers. When you include that header in more than one translation unit, you have multiple copies of the definition.

Only declare variables there (using extern), and define them in precisely one translation unit.

That said... an exception to this rule can be made for constants of built-in types, since they have internal linkage by default.

That is, the two programs are functionally identical:

const int x = 42;
int main() {}

static const int x = 42;
int main() {}

This ensures that one copy is generated for each translation unit, avoiding the issue altogether.

I think the same is true for arrays. So, sure, const it up and knock yourself out.


But as far as I know 'char* x' is equivalent to 'char x[]',

Only in a function parameter list. In a fully-fledged declaration, x will take the array type with dimension determined from the initialiser.

like image 36
Lightness Races in Orbit Avatar answered Oct 05 '22 23:10

Lightness Races in Orbit


You get the error because if you include the file in multiple compilation units, you are declaring a variable of that name in each unit. Compilation is not a problem, but when the linker tries to link it sees multiple definitions of the same variable. You can get away with this with const int variables and const char GAME_TITLE[] because they have static linkage, but for string literals (which are essentially char arrays) you will get this error. You should be able to fix the problem using extern

like image 44
mathematician1975 Avatar answered Oct 05 '22 23:10

mathematician1975