全局 const char * 上的错误 LNK1169

Posted

技术标签:

【中文标题】全局 const char * 上的错误 LNK1169【英文标题】:error LNK1169 on global const char* 【发布时间】:2012-12-07 22:44:13 【问题描述】:

我在使用 Visual Studio 2010 和 C++ 时遇到了一些奇怪的行为。 我有一个头文件,我在其中声明了一些全局常量

#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

我的问题在于以下行:

const char* CLASS_NAME = "WinMain";

当它是这样的时候,我构建了我的解决方案,我得到了以下 2 个错误:

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

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

现在很奇怪,因为运行了“在文件中查找”,我绝对不会在其他地方声明它,即没有重复声明。

我应该把它改成:

const char* const CLASS_NAME = "WinMain";

const char CLASS_NAME[] = "WinMain";

它编译得很好!但据我所知char* x 等同于char x[],而且我在指针和指向的值上都强制执行“const-ness”这一事实应该没有区别......或者是这样吗?

我对 Windows 平台上的 C++ 开发有点陌生,因此非常感谢任何帮助!

【问题讨论】:

SAFE_RELEASE 宏和它的朋友根本不安全。使用智能指针,不要自己deleteRelease() error LNK1169: one or more multiply defined symbols found的可能重复 @DeadMG 感谢您的建议! :) 【参考方案1】:

你的错误是你没有将你的常量声明为constants。在 C++ 语法中(以及在 C 中)为了声明一个常量指针,你必须这样做

const char* const CLASS_NAME = "WinMain";

请注意,您的 GAME_TITLEGAME_WIDTHGAME_HEIGHT 已正确声明为常量,这就是它们不会给您带来麻烦的原因。只有 CLASS_NAME 被错误地声明,即作为非常量。

默认情况下,C++ 中的常量具有内部链接,这就是为什么您可以在头文件中定义它们而不会违反单一定义规则。

【讨论】:

谢谢!!刚刚有一个尤里卡时刻! :) 哇,我从没想过这会是个问题。非常感谢:) 有人能解释一下为什么你需要两次“const”吗?比如,这是因为这是一个指向常量字符数组的常量指针,还是类似的东西? @aquirdturtle:你会从右到左阅读它,所以它是一个“指向常量字符的常量指针”。所以指针和该指针指向的值都不能改变。【参考方案2】:

不要在标题中定义变量。当您在多个翻译单元中包含该标题时,您将拥有该定义的多个副本。

仅在此处声明变量(使用extern),并在一个翻译单元中精确定义它们。

也就是说...对于内置类型的常量,可以对这条规则进行例外处理,因为它们默认具有内部链接。

也就是说,这两个程序在功能上是相同的:

const int x = 42;
int main() 

static const int x = 42;
int main() 

这确保为每个翻译单元生成一份副本,完全避免了这个问题。

认为数组也是如此。所以,当然,const 把自己搞砸了。


但据我所知'char* x'等价于'char x[]',

仅在函数参数列表中。在成熟的声明中,x 将采用数组类型,其维度由初始化程序确定。

【讨论】:

感谢您的回复! :) 只是关于您的评论的一个问题“当您在多个翻译单元中包含该标题时,您有多个定义副本。” #include 守卫不应该禁止这种行为吗? 我得到了这篇很酷的文章,它减轻了我对 char 指针的一些误解:cs.bu.edu/teaching/cpp/string/array-vs-ptr link :) @mnemonic:不。包含守卫只能在翻译单元中起作用。也就是说,它们可以防止由同一 .cpp 文件中的#include "hi.h" \n #include "hi.h" 引起的问题,或者包括其他头文件在内的头文件所达到的更复杂的等价物......包含保护,就像你的 C++ 代码的其余部分一样,不再存在于链接阶段。考虑集合1,2,3,33,4,5,5,6,6,您可以删除每个集合中的重复项以获得1,2,33,4,5,6,但是当您执行合并这些集合的最后一步时,您仍然有一个重复项:1,2,3,3,4,5,6。跨度> 啊,好吧!这就说得通了!谢谢! :) 还可以在 this example 中使用结构来声明/定义。希望它有所帮助。:)【参考方案3】:

您收到错误是因为如果您在多个编译单元中包含该文件,您将在每个单元中声明一个具有该名称的变量。编译不是问题,但是当链接器尝试链接时,它会看到同一个变量的多个定义。您可以使用const int 变量和const char GAME_TITLE[] 来解决这个问题,因为它们具有静态链接,但对于字符串文字(本质上是char 数组),您将收到此错误。您应该可以使用extern 解决问题

【讨论】:

以上是关于全局 const char * 上的错误 LNK1169的主要内容,如果未能解决你的问题,请参考以下文章

错误:无法使用“const char [34]”类型的左值初始化“const char”类型的返回对象

奇怪的错误,错误:从‘const char*’到‘char’的无效转换[-fpermissive]

c++错误:从不兼容的类型'const char *'分配给'char *'

错误 C2440:“=”:无法从“const char *”转换为“char *”

为啥 const QString& 参数返回错误的 const char* 指向数据的指针

从 unsigned const char * 类型转换为 char const *