C语言 如何避免全局常量的“多重定义”错误?

j13ufse2  于 2023-01-08  发布在  其他
关注(0)|答案(4)|浏览(222)

我正在用Windows API编写一个C程序,每个主要函数都有自己的文件,原型和包含等都有一个头文件:

// 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);

让我恼火的是#define szClassName行,我不喜欢使用宏,希望有一个合适的全局变量wchar_t szClassName[],但如果我这样做,链接器会抱怨在包含头部的每个模块中有多个定义的变量。
我以为#pragma once指令可以防止这种情况,但它没有。
这个问题有什么解决办法吗?

lx0bsm1f

lx0bsm1f1#

这个问题的解决方案是有一个单独的声明和定义...
表头(*.h;对不起,我不知道WinAPI类型名称,请根据需要进行修改):

extern const char szClassName[];

实现(*.c或 *.cpp)

const char szClassName[] = "hello, world"

您之所以看到这个问题,是因为每当您的 *.c或 *.cpp文件之一包含头文件时,就会声明一个新的符号szClassName(即使使用了include guard!);这使得连接器混乱(见下文)。
请注意,这将使sizeof(szClassName)不再工作。

进一步解释:

预处理之后,编译器基本上会看到:

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

当链接器链接对象文件(比如“a.obj”、“b.obj”和“c.obj”)时,它看到相同的符号被定义了一个新值(至少对于链接器来说是这样)---因此它会失败,并返回一个错误。

tzcvj98z

tzcvj98z2#

把它放在中间

#ifndef GLOB_CONST_H
#define GLOB_CONST_H 

// All macro definitions
// and type definitions

#endif

使用extern关键字来声明你的全局变量,并把这些声明放在这个头文件中。然后你需要把所有变量的定义放在一个.c文件中。

f3temu5u

f3temu5u3#

你可以将变量声明为static,这样每个包含.h文件的模块都有自己的本地唯一副本,链接器不会抱怨,因为每个副本都有本地链接而不是外部链接。这也消除了将变量声明为extern并在单独的.c文件中定义它的需要。

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

或;

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

或者:

static LPCTSTR szClassName = TEXT("EthicsPresentationWnd");
jyztefdp

jyztefdp4#

在所有的头文件中使用头保护,在.c文件中声明一个全局变量,并在头文件中声明该全局变量的extern。

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

在任何一个.c文件中定义全局变量。

wchar_t szClassName[];

相关问题