Andy Niu Help
1.0.0.0
|
详细描述
变量说明
error_LNK2005 |
1、错误原因:链接的时候,发现重复定义。 2、比如:在a.cpp和b.cpp中都定义方法如下: int doSth(int a) { return a+1; } 3、编译报错,b.obj : error LNK2005: "int __cdecl doSth(int)" (?doSth@@YAHH@Z) 已经在 a.obj 中定义 链接的时候,发现b.obj中的doSth方法已经在a.obj中定义,重复定义。
NULL指针初始化string |
1、报错: terminate called after throwing an instance of 'std::logic_error' what(): basic_string::_S_construct NULL not valid 2、错误原因:对一个空指针进行操作。如下: char* p = NULL: string str(p); //运行时报错
- 参见
Stack_overflow |
错误原因:栈上分配了太多的内存,栈的内存一般只有1M。 错误代码: char tmp[1024*1024*10];
- 参见
vector_subscript_out_of_range |
1、错误原因,vector下标越界。 2、代码如下: int main(int argc, char* argv[]) { vector<int> intVec; intVec.push_back(1); int ff = intVec[1]; getchar(); } 3、VS弹出错误窗口,Debug Assertion Failed! 这时候,点击重试,触发一个断点,点击中断,在调用堆栈即可找到错误的代码行。 注意:VS弹出错误窗口,千万不能点击中止,否则的话,程序直接关闭,看不到错误的代码行。 4、另外有几个单词,需要注意一下: script 脚本 subscript 下标 scribe 抄写员 subscribe 订阅
vector重复定义 |
1、测试代码如下: a.h #ifndef A_H_ #define A_H_ #include "b.h" class A { public: int _Id; B _B; }; #endif b.h #ifndef B_H_ #define B_H_ #include <vector> using namespace std; vector<int> aVec; class B { public: int _Id; }; #endif 也就是说,A包含B的头文件,而在B的头文件中定义了一个aVec; 同时还有a.cpp、b.pp以及main.cpp a.cpp #include "a.h" b.cpp #include "b.h" main.cpp #include "a.h" int main(int argc, char* argv[]) { A a; return 0; } 2、编译报错如下: 1>a.obj : error LNK2005: "class std::vector<int,class std::allocator<int> > aVec" (?aVec@@3V?$vector@HV?$allocator@H@std@@@std@@A) 已经在 main.obj 中定义 1>b.obj : error LNK2005: "class std::vector<int,class std::allocator<int> > aVec" (?aVec@@3V?$vector@HV?$allocator@H@std@@@std@@A) 已经在 main.obj 中定义 1>D:\Temp\NiuzbRepository\trunk\C++\CppTest\Debug\TestStatic.exe : fatal error LNK1169: 找到一个或多个多重定义的符号 3、错误原因,vs已经说的很清楚,就是aVec重复定义了。 原因是:在头文件定义aVec,被多个编译单元包含,每个编译单元都一个aVec的定义,重复定义。 链接的时候,每个编译单元都是外部链接,这么多aVec,不知道该使用了哪个aVec。 4、表面一看,上面报错的错误比较奇怪,一大堆信息,不容易看清楚,要仔细读一遍,才能找出关键信息,aVec重复定义。 我们换成一个int就很清楚了。如下: b.h #ifndef B_H_ #define B_H_ int hhh; class B { public: int _Id; }; #endif 报的错误如下: 1>a.obj : error LNK2005: "int hhh" (?hhh@@3HA) 已经在 main.obj 中定义 1>b.obj : error LNK2005: "int hhh" (?hhh@@3HA) 已经在 main.obj 中定义 1>D:\Temp\NiuzbRepository\trunk\C++\CppTest\Debug\TestStatic.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
VS调试报错:不是内部或外部命令,也不是可运行的程序或批处理文件 |
1、错误原因是什么? 我们运行一个程序,会引用其它的库文件或者调用其它的命令,必须告诉操作系统,这个程序所依赖的库文件和命令在哪个地方。 如果没有告诉操作系统,对于引用的库文件,报错:无法启动此程序,因为计算机中丢失xxx.dll 对于调用的命令(也就是执行其它的程序),报错:不是内部或外部命令,也不是可运行的程序或批处理文件 2、怎么解决这个问题: 必须告诉操作系统,所依赖的库文件和命令在哪个地方。windows下就是path VS调试的时候,在工程属性-->调试-->环境,增加 path=../common;c:/windows/system32; 使用批处理运行,在开头增加 path=../common;%path%; 注意:在linux下使用 export LD_LIBRARY_PATH=../common; 3、在构建工程的时候,对于编译时引用的头文件和连接时引用的lib文件,是同样的道理,必须告诉头文件和lib文件在哪个目录。 头文件的设置在: 在工程属性-->C/C++-->常规-->附加包含目录 lib文件的设置在:在工程属性-->链接器-->常规-->附加库目录
不是类或命名空间名称 |
1、今天遇到一个奇怪的问题,使用一个类,并且引用了对应的头文件,但是奇怪的是, 报错error C2653: "ibpUtils": 不是类或命名空间名称。 2、仔细思考,为什么? include "xxx.h" 就是对xxx.h进行文本替换。这就存在问题,重复引用同一个头文件,会导致头文件中的内容重复定义。 谁会很傻地重复引用同一个头文件呢?如下: include "xxx.h" include "xxx.h" 这种很傻瓜的错误当然可以避免,但是有一种情况,却很难避免,间接地导致重复引用同一个头文件。比如: a.h 引用头文件 b.h c.h 引用头文件 a.h和b.h,由于c.h无法知道a.h已经引用了b.h,因此会 include "a.h" include "b.h" 编译器对include会递归地进行替换,也就是先替换a.h,对于a.h中的include "b.h" 再次替换, 这就导致了b.h的内容重复出现在c.h中。 3、怎么解决这个问题? 使用头文件保护符,如下: #ifndef _XXX_H_ #define _XXX_H_ ...... #endif 这就保证了不会重复包含同一个头文件。 4、但是,有一点需要特别注意。那就是:头文件保护符不能有重复的宏,如果出现重复的宏,就会导致下一个头文件不能被包含进来。 5、现在问题有思路了,既然明明包含了头文件,却找不到对应的类或命名空间,肯定是存在头文件保护符相同,导致了没有被包含进来。 6、解决办法:ibpUtils不存在,找到ibpUtils对应的头文件,搜索头文件保护符,果然有重复的头文件保护符
- 参见
已经在LIBCMTD_lib中定义 |
1、错误信息如下: 1>MSVCRTD.lib(MSVCR80D.dll) : error LNK2005: _printf 已经在 LIBCMTD.lib(printf.obj) 中定义 2、错误原因: 使用不同的库,而这些库使用不同的运行时库,在这些运行时库中,对同一个方法都有实现,导致这些方法重复定义。 3、解决办法: 使用相同的运行时库。在属性-->C/C++-->代码生成-->运行时库 libcmt对应多线程的静态库 msvcr80对应多线程的动态库 其中d表示debug版本。 4、还有一种解决办法: 忽略某一个特定的库,这种办法可能存在问题,不建议使用。
无法从char指针转换为string引用 |
1、代码如下: char tmp[64]; sprintf(tmp,"Andy"); string aa = tmp; string& bb = tmp; const string& cc = tmp; 2、其中string& bb = tmp; 报错 error C2440: “初始化”: 无法从“char [64]”转换为“std::string &” 3、思考为什么? 4、string aa = tmp; 左边string会调用构造方法,右边是char*,string存在构造方法接收char*,因此会调用string的构造方法。 上面的语句等价于 string aa(tmp); 5、string& bb = tmp; 左边是string的引用,期望接收string对象,但是右边不是string对象,这个时候要产生一个中间对象, 也就是临时对象,但是这个临时对象是const对象,const对象不能赋值给非const的引用。 这就能解释为什么const string& cc = tmp; 是正确的。 6、那么为什么中间的临时对象是const对象呢? 假定中间的临时对象不是const对象,string& bb = tmp 是正确的,那么,程序员操作bb="hello", 期望会修改tmp的值,我们知道这是不可能的,因为修改的是临时对象,与tmp完全不搭嘎。 也就是说,中间的临时对象不是const对象,会导致与程序员期望不一致的结果, 为了避免这个问题,中间的临时对象是const对象。 7、注意:string aa = tmp; 存在隐式类型转化,直接调用对应的构造方法,但是不存在中间的临时对象。
- 参见
无法定位程序输入点 |
1、错误原因:动态加载的时候无法找到VTDU_A_SetResMsgCallBack方法的实现。
无法打开文件LIBC_lib问题 |
1、错误原因: 如果将用低版本的VC开发的项目,拿到高版本的VC开发环境上去编译,链接时也许会触发LNK1104错误,如下: 1>LINK : fatal error LNK1104: 无法打开文件“LIBC.lib” 2、解决办法:链接时忽略此库,在此提供两种解决方案: Project | Properties | Configuration Properties | Linker | Input Ignore Specific Library: libc.lib 或 #pragma comment(linker, "/NODEFAULTLIB:libc.lib")
无法打开文件vld_lib |
fatal error LNK1104: 无法打开文件vld.lib 1、今天发现一个很奇怪的问题,具体的场景是: cmu_sdk(动态库)---> ibp_utils(动态库)---> vld(动态库) 2、现在修改ibp_utils,不依赖vld,重新编译ibp_utils和cmu_sdk,结果发现: cmu_sdk链接的时候报错:fatal error LNK1104: 无法打开文件 vld.lib 3、错误原因是:cmu_sdk还在试图去连接vld.lib 4、这是为什么呢? 思考,cmu_sdk去连接的库,包含两部分:直接依赖的库和间接依赖的库 间接依赖的库也就是,依赖一个静态库,而这个静态库又依赖其它的库,也就是说,当前库间接依赖其它库。 5、仔细查找,果然发现cmu_sdk(动态库)--->new_ibp_protocol(静态库)--->ibp_utils(动态库)---> vld(动态库) 6、重新编译new_ibp_protocol静态库,再次编译cmu_sdk,结果OK
无法解析的外部符号 |
1、错误原因:链接的时候,找不到方法的实现。 2、但是整个解决方案都搜索不到 SetModuleName 3、仔细分析,对于当前类的方法,只有声明,没有定义,如果没有调用方法,不会报错。 4、但是对于继承,比如 VruMaster继承了ibpMaster。 ibpMaster声明了虚方法,没有定义,即使没有调用方法,子类构建,也会链接失败。 5、因此,可以断定VruMaster 引用的头文件有SetModuleName 这个虚方法的声明。
模拟CPP程序崩溃 |
1、在项目中经常遇到C++程序崩溃,这些崩溃都是有原因的,往往是因为自己对C++使用不当造成的,模拟C++崩溃的场景。 2、除0,如下: int main(int argc, char* argv[]) { return 1/0; } 编译: [root@localhost dump]# g++ -o main main.cpp main.cpp: In function ‘int main(int, char**)’: main.cpp:3: warning: division by zero in ‘1 / 0’ 编译已经给出警告 [root@localhost dump]# ./main Floating point exception 没有生成core文件,原因是没有设置ulimit -c,ulimit -c表示程序错误,把程序在内存中的信息转存到文件。如下: [root@localhost dump]# ulimit -c 0 [root@localhost dump]# ulimit -c 1000 [root@localhost dump]# ./main Floating point exception (core dumped) [root@localhost dump]# ll total 112 -rw------- 1 root root 196608 Jan 28 17:53 core.27550 -rwxr-xr-x 1 root root 4863 Jan 28 17:49 main -rwxrwxrwx 1 root root 50 Jan 28 17:46 main.cpp dump转存的时候,如果程序在内存的大小,超过-c的设置,就不会产生dump文件,因此要把-c设置很大,最好不限制。如下: [root@localhost dump]# ulimit -c unlimited 3、上面已经是很短的崩溃程序,能不能更短呢? int main=0; 崩溃原因:程序会试图按照调用方法的方式去执行main,这当然不行。 4、栈溢出(stack overflow) #include <stdio.h> int main(int argc, char* argv) { char pc[1024*1024*1024*2]; getchar(); return 0; } 编译报错,如下: [root@localhost dump]# g++ -o main main.cpp main.cpp: In function ‘int main(int, char*)’: main.cpp:4: error: overflow in constant expression main.cpp:4: error: size of array ‘pc’ is negative 编译器很聪明,因为栈的大小一般为1M,这里是2M,直接编译报错。需要糊弄一下编译器,如下: #include <stdio.h> int main(int argc, char* argv) { int size = 1024*1024*1024*2; char pc[size]; getchar(); return 0; } 5、踩内存 #include <string.h> int main(int argc, char* argv) { int a =10; char pc[4] = {0}; strcpy(pc,"aaaaaaaaaaaaaaa"); a = a+10; return 0; } 或者 #include <memory.h> int main(int argc, char* argv) { int a =10; char pc[4] = {0}; char* pc2 = "aaaaaaaaaaaaaaa"; memcpy(pc,pc2,strlen(pc2)); a = a+10; return 0; }
系统类型fd_set重复定义 |
1、今天遇到一个很奇怪的问题,如下: error C2011: “fd_set”: “struct”类型重定义 2、发现是因为包含某个头文件导致的。调整一下头文件的包含顺序,发现就正常了。为什么呢? 3、include头文件,本质上就是文本替换(替换的过程中,会根据宏进行条件判断,是否包含,是否编译) 不同的include顺序会导致不同的结果。 4、举例来说: a.h #ifndef A_H_ #define A_H_ struct AAA { }; #endif b.h #ifndef B_H_ #define B_H_ #ifndef A_H_ struct AAA { }; #endif #endif 5、考虑a.h与b.h不同的include顺序,a,b顺序没有问题,b,a导致AAA重复定义。
- 参见
踩内存导致delete的时候崩溃 |
1、今天遇到一个奇怪的问题,delete的时候程序崩溃。new出来的内存,只是释放一次,并没有多次释放。 2、思考为什么? delete崩溃,说明要释放的堆内存已经损坏。损坏的原因有很多,比如踩内存。比如: char* aaa = new char[4]; sprintf(aaa,"1111111111"); delete []aaa;
野指针可能不会立即崩溃,会导致未定义行为 |
1、测试代码 #include <string> using namespace std; class Person { public: int _Age; string _Name; }; int main() { Person* p = new Person(); p->_Age = 18; p->_Name = "Andy"; delete p; p->_Age = 20; p->_Name = "Bill"; return 0; } 2、delete p; 之后,p是野指针, p->_Age = 20; 不会导致崩溃 而p->_Name = "Bill"; 会导致崩溃,崩溃信息如下: NzbUtils.exe 中的 0x57b6d5a8 (msvcr80d.dll) 处未处理的异常: 0xC0000005: 写入位置 0xfeeefeee 时发生访问冲突 3、这是因为在VS的Debug模式,delete p之后,内存信息都是 0x fe ee fe ee 4、也就是说,对于野指针的操作,比如p->_Age = 20; 不会导致崩溃,但是会产生未定义的行为,很难定位到问题。 5、怎么解决这个问题? delete p之后,马上赋值为NULL,再对p操作,马上就崩溃。崩溃如下: NzbUtils.exe 中的 0x00411ce0 处未处理的异常: 0xC0000005: 写入位置 0x00000000 时发生访问冲突 6、以上是在VS测试的,在linux使用g++测试,对于野指针的操作, delete p; p->_Age = 20; p->_Name = "Bill"; 都不会崩溃 7、因此,野指针的问题非常严重,会导致不确定的行为。不知道什么时候崩溃,以及在哪里崩溃。 一定要避免野指针的问题,也就是delete之后,马上赋值为NULL
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.