0

I'm writing a C program using the Windows API. Each major function has its own file, and there is one header for the prototypes and includes and whatnot:

// Headers & global constants
#pragma once
#define _WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WindowsX.h>
#include <Windef.h>

#define szClassName TEXT("EthicsPresentationWnd")
// Prototypes
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK FontProc1(HWND hWnd, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
ATOM RegisterWindow(HINSTANCE hInstance);

The thing I'm irritated about is the #define szClassName line. I dislike using macros and would prefer to have a proper global variable, wchar_t szClassName[], but if I do that then the linker complains about multiply defined variables in each of the modules that include the header.

I thought the #pragma once directive would prevent this, but it didn't.

Is there any solution to this problem?

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85

4 Answers4

5

The solution to this is to have a separate declaration and definition...

Header (*.h; sorry, I don't know WinAPI type names, adapt as necessary):

extern const char szClassName[];

Implementation (*.c or *.cpp)

const char szClassName[] = "hello, world"

You're seeing the problem because a new symbol szClassName is being declared each time one of your *.c or *.cpp files includes the header (even with the include guards!); and that makes the linker confused (see below).

Do note that this will make sizeof(szClassName) not work anymore.

Further explanation:

After preprocessing, the compiler is basically seeing this:

  • file "a.c": const char someSymbol[] = <some text, don't care what right now>;
  • file "b.c": const char someSymbol[] = <some text, don't care if it's the same>;
  • file "c.c": const char someSymbol[] = <some text, ditto>;

When the linker is linking the object files (say, "a.obj", "b.obj" and "c.obj"), it sees the same symbol being defined with a new value (at least as far as the linker is concerned) --- and thus it fails with an error.

Community
  • 1
  • 1
Tim Čas
  • 10,501
  • 3
  • 26
  • 32
1

Place it in between

#ifndef GLOB_CONST_H
#define GLOB_CONST_H 

// All macro definitions
// and type definitions

#endif   

Use extern keyword to declare your global variables and put those declarations in this header file. After that you need to place the definition of all the variables in a .c file.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • 2
    Header guards won't help him. `#pragma once` takes care of the header guarding; this is a linker, not compiler, error (see my answer). – Tim Čas Jul 12 '14 at 20:40
1

Use header guards in all your header file and declare a global variable in .c file and declare extern to that global variable in a header file.

#ifndef HEADER_FILE_NAME_H    /* if not defined already */
#define HEADER_FILE_NAME_H
extern wchar_t szClassName[];
#endif

In any one of your .c file define the global variable.

wchar_t szClassName[];
jshep321
  • 553
  • 5
  • 8
1

You can declare the variable as static so that each module that includes the .h file gets its own local unique copy that the linker will not complain about, as each copy will have local linkage instead of external linkage. This also eliminates the need for declaring the variable as extern and defining it in a separate .c file.

static const TCHAR szClassName[] = TEXT("EthicsPresentationWnd");

Or;

static const TCHAR *szClassName = TEXT("EthicsPresentationWnd");

Or:

static LPCTSTR szClassName = TEXT("EthicsPresentationWnd");
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    I think this falls under the category of "do not attempt unless you're sure you know what are doing". Having multiple modules with separate copies of a variable that is declared once seems like a bad idea to me. – Stuart Jul 14 '14 at 17:46