解决出现的LNK2005“符号已定义”错误

许多Visual C++的使用者都碰到过LNK2005:symbol already defined和LNK1169:one or more multiply defined symbols found这样的链接错误,而且通常是在使用第三方库时遇到的。对于这个问题,有的朋友可能不知其然,而有的朋友可能知其然却不知其所以然,那么本文就试图为大家彻底解开关于它的种种疑惑。

大家都知道,从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器(assembler)翻译成机器指令(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。

编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号。比如有这么个源文件:

extern int errorno;
int buf[2] = {1,2};
int *p;
  int main()
{

return 0;
}

其中main、buf是强符号,p是弱符号,而errorno则非强非弱,因为它只是个外部变量的使用声明。

有了强弱符号的概念,我们就可以看看链接器是如何处理与选择被多次定义过的全局符号:

规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);

规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;

规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个;

由上可知多个目标文件不能重复定义同名的函数与初始化了的全局变量,否则必然导致LNK2005和LNK1169两种链接错误。可是,有的时候我们并没有在自己的程序中发现这样的重定义现象,却也遇到了此种链接错误,这又是何解?嗯,问题稍微有点儿复杂,容我慢慢道来。

众所周知,ANSI C/C++ 定义了相当多的标准函数,而它们又分布在许多不同的目标文件中,如果直接以目标文件的形式提供给程序员使用的话,就需要他们确切地知道哪个函数存在于哪个目标文件中,并且在链接时显式地指定目标文件名才能成功地生成可执行文件,显然这是一个巨大的负担。所以C语言提供了一种将多个目标文件打包成一个文件的机制,这就是静态程序库(static library)。开发者在链接时只需指定程序库的文件名,链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块,并把(且只把)它们从库中拷贝出来参与构建可执行文件。几乎所有的C/C++开发系统都会把标准函数打包成标准库提供给开发者使用(有不这么做的吗?)。

程序库为开发者带来了方便,但同时也是某些混乱的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的。

在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,E、U、D都是空的。

(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。

(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。

(3): 如果处理过程中往D加入一个已存在的符号,或者当扫描完所有输入文件时U非空,链接器报错并停止动作。否则,它把E中的所有目标文件合并在一起生成可执行文件。

时间: 2024-11-02 14:13:09

解决出现的LNK2005“符号已定义”错误的相关文章

java-eclipse中,定义类Employee时,错误提示是“已定义类型Employee”,该如何进行解决?

问题描述 eclipse中,定义类Employee时,错误提示是"已定义类型Employee",该如何进行解决? public class ParamTest { public static void main(String[] args) { System.out.println("tripleValue testing"); double percent=10; System.out.println("Before:percent="+per

求教如何解决C#调用C++ DLL出现“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”错误

问题描述 我正在编写设备处理程序,使用C++写的DLL,其中一个部分需要用到回调函数.现在遇到的问题是使用InitDevice()函数后,回调函数能够正常运行获取返回数据,但是随后调用Close()函数,就会导致系统报出"尝试读取或写入受保护的内存.这通常指示其他内存已损坏"错误.使用了N种方式也没有解决这个问题,有哪位高手能够帮帮忙啊!C++函数原形如下:extern"C"__declspec(dllexport)HANDLE__stdcallLogin(cons

web-ASP.NET错误 6 类型已定义了一个名为“Page_Load”的具有相同参数类型的成员

问题描述 ASP.NET错误 6 类型已定义了一个名为"Page_Load"的具有相同参数类型的成员 错误 6 类型"Web_MetenLive.zhuanti.Chongqing.Inf02"已定义了一个名为"Page_Load"的具有相同参数类型的成员 E:项目MetenSiteMetenSiteMetenSiteMetenSite.Web(MetenLive)zhuantiChongqingInf02.aspx.cs 12 24 Meten

CentOS下PureFtp出现“数据 Socket 错误 连接已超时”错误解决办法

前段时间配置了PureFTP上传程序,但期间出现种种让人不爽的问题!比如在本地使用 FlashFTP 时出现最多的"数据 Socket 错误 连接已超时"错误,无论使用主动还是被动模式上传,都会有类似错误! [右] 数据 Socket 错误: 没有到主机的通道 [右] 列表 错误 [右] PASV [右] 227 Entering Passive Mode (116,255,246,176,83,197) [右] 正在打开数据连接 IP: 116.255.246.176 端口: 214

socket-【C++】符号重定义,头文件包含问题

问题描述 [C++]符号重定义,头文件包含问题 #pragma once #include "Common.h" #include "WinSock.h" class CSockOperation { public: int Send(SOCKET socket,const char* buf,int len);//失败返回错误值 int Recv(SOCKET socket,char* lpBuf,int nBufLen);//失败返回错误值 int CSockO

Mysql中避免“表已满错误”出现

表已满错误出现的方式有数种: ·你正在使用低于3.23版的MySQL服务器,而且"内存中"临时表超过了tmp_table_size字节.要想避免该问题,可使用"-O tmp_table_size=val"选项以便mysqld增加临时表的大小,或在发出有问题的查询之前,使用SQL选项SQL_BIG_TABLES. 也可以使用"--big-tables"选项启动mysqld.它与使用针对所有查询的SQL_BIG_TABLES完全相同. 自MySQL

解决jquery中美元符号命名冲突问题

 在Jquery中,$是JQuery的别名,所有使用$的地方也都可以使用JQuery来替换,下面为大家介绍下如何解决jquery中美元符号命名冲突问题 在Jquery中,$是JQuery的别名,所有使用$的地方也都可以使用JQuery来替换,如$('#msg')等同于JQuery('#msg') 的写法.然而,当我们引入多个js库后,在另外一个js库中也定义了$符号的话,那么我们在使用$符号时就发生了冲突.下面以引入两个库文件 jquery.js和prototype.js为例来进行说明.   

如何在asp.aspx加个代码,程序一出错就跳转到我的自己定义错误页面去

问题描述 如何在asp.aspx加个代码,程序一出错就跳转到我的自己定义错误页面去 请帮助下啊,我用NET2008,C#SQL2008编了个程序,就是每当输入不合法或者Session失效或者等等问题出错,程序就象死机了一样,不能用,只有关掉软件重开才行,现请帮助解决一下,程序不论出什么错都自动跳转到我的自己定义错误页面去,在百度上查了,在WEB.CONFIG里加错误处理也不行,早些时候在百度上找了一些代码加在asp.aspx页面上是能解决问题,但现在怎么也找不到这个代码,搜索到的全是设置web.

多线程-vs2015类型重定义错误

问题描述 vs2015类型重定义错误 c实现多线程发生错误.安装pthread后,运行出现错误,错误为:c2011 "timespec":"struct"类型重定义.错误头文件是pthread.h.怎么解决啊?谢谢各位了! 解决方案 将#include <windows.h>放在#include<winsock2.h>之后 解决方案二: 长见识了,VS链接中的重定义错误VS2008里 struct 类型重定义 错误VS2008里 struct