全局 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 宏和它的朋友根本不安全。使用智能指针,不要自己delete
或Release()
。
error LNK1169: one or more multiply defined symbols found的可能重复
@DeadMG 感谢您的建议! :)
【参考方案1】:
你的错误是你没有将你的常量声明为constants。在 C++ 语法中(以及在 C 中)为了声明一个常量指针,你必须这样做
const char* const CLASS_NAME = "WinMain";
请注意,您的 GAME_TITLE
、GAME_WIDTH
和 GAME_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,3
和3,4,5,5,6,6
,您可以删除每个集合中的重复项以获得1,2,3
和3,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 *”