c++开发遇到的错误和引用配置
1
libcurl引入的时候必须要加载下面三个库
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "crypt32.lib" )
32位程序需要引入前两个,64位程序需要引入这三个
然后要在property pages->c/c++->preprocessor->preprocessor definitions
中添加CURL_STATICLIB
不然会报下面的错误
error LNK2001: unresolved external symbol __imp_curl_easy_perform
error LNK2001: unresolved external symbol __imp_curl_global_init
error LNK2001: unresolved external symbol __imp_curl_global_cleanup
error LNK2001: unresolved external symbol __imp_curl_easy_init
error LNK2001: unresolved external symbol __imp_curl_easy_cleanup
error LNK2001: unresolved external symbol __imp_curl_easy_setopt
2
fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?}
Configuration Properties->C/C++->Precompiled Headers->Precompiled Header->Not Using Precompiled Headers
3
#pragma comment(lib, "shlwapi.lib")
后面必须跟lib名字,不可以加路径,如果要指定路径,那就在工程中配置对应lib的引用路径
4
网络编程中如果出现
error C2011: 'sockaddr' : 'struct' type redefinition
类似的编译错误,原因就是因为在#include <WinSock2.h>
前面包含了#include <Windows.h>
因为#include <Windows.h>
中包含了#include <winsock.h>
,而#include <winsock.h>
中定义了与#include <WinSock2.h>
一样名字的类型。现在都是#include <WinSock2.h>
,#include <winsock.h>
是比较老的功能了。名字一样但是里面的结构可能有区别,就导致报错。修改方法就是查看所有工程中引用#include <Windows.h>
和#include <WinSock2.h>
的地方,确保#include <WinSock2.h>
在#include <Windows.h>
前面。不仅仅是直接引用,也包括间接引用,比如你在引用#include <WinSock2.h>
之前引用了其他头文件,其他头文件中引用了#include <Windows.h>
,这样也是会报错
也可以在所有的引用最前面或是所有#include <Windows.h>
前面定义#define _WINSOCKAPI_
,因为在#include <winsock.h>
通过#define _WINSOCKAPI_
来判断是否引用这个头文件,所以可以提前定义让它不引用就可以了
5
如果使用#define _WINSOCKAPI_
来解决上面的问题,那么有可能导致curl的编译错误
<path to curl source>\curl\include\curl\curl.h(134,29): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\curl.h(134,16): error C2146: syntax error: missing ';' before identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(397,52): error C2061: syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(407,23): error C2079: 'curl_sockaddr::addr' uses undefined struct 'sockaddr'
<path to curl source>\curl\include\curl\curl.h(411,3): error C2065: 'curl_opensocket_callback': undeclared identifier
<path to curl source>\curl\include\curl\curl.h(411,27): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\curl.h(411,27): error C2378: 'curl_socket_t': redefinition; symbol cannot be overloaded with a typedef
<path to curl source>\curl\include\curl\curl.h(134): message : see declaration of 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(411,28): error C2513: 'int': no variable declared before '='
<path to curl source>\curl\include\curl\curl.h(411,28): error C2143: syntax error: missing ';' before '('
<path to curl source>\curl\include\curl\curl.h(411,34): error C2062: type 'void' unexpected
<path to curl source>\curl\include\curl\curl.h(416,59): error C2061: syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(113,19): error C3646: 'fd': unknown override specifier
<path to curl source>\curl\include\curl\multi.h(113,19): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\multi.h(157,47): error C2061: syntax error: identifier 'fd_set'
<path to curl source>\curl\include\curl\multi.h(271,51): error C2061: syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(292,76): error C2061: syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(296,62): error C2061: syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(410,55): error C2061: syntax error: identifier 'curl_socket_t'
跟踪进去发现SOCKET相关的定义有问题,头文件感觉被屏蔽了。具体原因没仔细看,大体就是上面的宏把curl头文件中的一些内容屏蔽了。解决方法就是要么在curl头文件之后再调用宏,要么就是不使用宏,使用上面的第一种方法,调整好windows.h
和winsock2.h
的顺序
6
使用string_view的时候需要c++17的支持。visual studio 2017已经支持。需要在
configuration properties->c/c++->language->c++ language standard选择引用
7
error C2872: 'byte': ambiguous symbol
使用c++17的时候,如果你使用了byte,那么会报这个错误。
https://github.com/OneLoneCoder/videos/pull/4/commits/bda99ec13d1989c1a67fada8fbebf7e059c47ec5
就是在c++17的标准模板库(std)中定义了byte,与c++的byte冲突。在上面的内容中提到了解决方法。
主要思路就是避免在使用byte的时候有误解。我是通过下面的方法解决的。就是把using namespace std;
移动一下,放到头文件最后面或是只在对应的cpp文件中使用。这样std的byte要通过std::byte调用,就可以避免这个问题了
8
R6025 - pure virtual function call
这个是调用了没有实现的纯虚函数
一般情况下编译器会报错,编译不过,但是如果在纯虚函数的基类构造函数或是析构函数调用了这个方法,那么子类继承,创建子类的时候就会先初始化基类,基类构造的时候调用了这个方法,但是这个时候子类还没有构造,所以子类对这个纯虚函数的实现还没有走到,导致基类在构造函数调用了纯虚的没有实现的函数。或是在析构函数中,因为子类的实现已经释放了资源,所以基类调用也会报错
/* Compile options needed: none
*/
class A;
void fcn( A* );
class A
{
public:
virtual void f() = 0;
A() { fcn( this ); }
};
class B : A
{
void f() { }
};
void fcn( A* p )
{
p->f();
}
// The declaration below invokes class B's constructor, which
// first calls class A's constructor, which calls fcn. Then
// fcn calls A::f, which is a pure virtual function, and
// this causes the run-time error. B has not been constructed
// at this point, so the B::f cannot be called. You would not
// want it to be called because it could depend on something
// in B that has not been initialized yet.
B b;
void main()
{
}
还有另一种情况,都是正常,在基类构造函数内没有调用纯虚函数,但是在基类的析构函数内抛出了一个异常,导致子类没有完全释放内存,保留了一部分残留,这个时候如果调用野指针,也会导致这个问题
class base
{
public:
base(){}
virtual void virtualfunc() = 0;
~base(){throw 0;}
};
class derrived:public base
{
public:
virtual void virtualfunc(){printf(">>>");};
};
int _tmain(int argc, _TCHAR* argv[])
{
base * pb = new derrived;
try
{
delete pb;
pb = NULL;
}
catch (...)
{
}
pb->virtualfunc();
return 0;
}
所以在构造和析构函数中,不要做太复杂的操作,仅仅是对成员变量的赋值和回收。不然会有很多莫名其妙的bug,可以增加初始化函数和结束函数,用来在类创建完成和释放前调用。
9
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
如果指定某个类没定义,那么一般是头文件引用问题,保证好相互引用的几个类的头文件引用顺序。因为在定义一个类的变量时,并没有引用这个类或是提前声明,导致编译器不知道这个类是什么类型
10
_ASSERTE(_CrtCheckMemory());
操作内存前后,调用一下,会检查目前内存有没有问题,比如内存泄露,野指针
11
c++操作符返回引用,是因为必须要返回自己,所以只能要返回引用
class TestClass {
private:
int number;
public:
TestClass& operator+=(const TestClass& rhs) {
number += rhs.number;
return *this;
}
};
我们就是要返回自己的+=,而不是返回一个自己的拷贝
12
VS运行时库 /MD
、/MDd
和 /MT
、/MTd
之间的区别
/MT
是 "multithread, static version" 意思是多线程静态的版本,定义了它后,编译器把LIBCMT.lib 安置到OBJ文件中,让链接器使用LIBCMT.lib 处理外部符号。
/MD
是 "multithread- and DLL-specific version” ,意思是多线程DLL版本,定义了它后,编译器把MSVCRT.lib 安置到OBJ文件中,它连接到DLL的方式是静态链接,实际上工作的库是MSVCR80.DLL。
即:
静态运行时库:LIBCMT.lib
动态运行时库:MSVCRT.lib + MSVCR80.DLL
所以,当你用CMAKE生成工程文件时,若CMAKE是用/MT生成的(查看工程原始目录的CMakeLists.txt),则它所调用的运行时库为:LIBCMT.lib,若生成的工程的运行时库(Runtime Library)你选择/MD,则此工程在编译后链接的时候,将会调用动态运行时库:MSVCRT.lib + MSVCR80.DLL,明显,两次对同一个某运行时库里的函数调用的库不同,则会出现重定义的错误。若此工程生成的是库文件,则其他工程调用此库时也必须是/MT。
其中以小写“d”结尾的选项表示的DEBUG版本的,没有“d”的为RELEASE版本。大型项目中必须要求所有组件和第三方库的运行时库是统一的,否则将会出现LNK2005井喷。
单线程运行时库选项/ML和/MLd在VS2003以后就被废了。
/MT和/MTd表示采用多线程CRT库的静态lib版本。该选项会在编译时将运行时库以静态lib的形式完全嵌入。该选项生成的可执行文件运行时不需要运行时库dll的参加,会获得轻微的性能提升,但最终生成的二进制代码因链入庞大的运行时库实现而变得非常臃肿。当某项目以静态链接库的形式嵌入到多个项目,则可能造成运行时库的内存管理有多份,最终将导致致命的“Invalid Address specified to RtlValidateHeap”问题。另外托管C++和CLI中不再支持/MT和/MTd选项。
/MD和/MDd表示采用多线程CRT库的动态dll版本,会使应用程序使用运行时库特定版本的多线程DLL。链接时将按照传统VC链接dll的方式将运行时库MSVCRxx.DLL的导入库MSVCRT.lib链接,在运行时要求安装了相应版本的VC运行时库可再发行组件包(当然把这些运行时库dll放在应用程序目录下也是可以的)。 因/MD和/MDd方式不会将运行时库链接到可执行文件内部,可有效减少可执行文件尺寸。当多项目以MD方式运作时,其内部会采用同一个堆,内存管理将被简化,跨模块内存管理问题也能得到缓解。
结论:/MD和/MDd将是潮流所趋,/ML和/MLd方式请及时放弃,/MT和/MTd在非必要时最好也不要采用了。
13
编译完,如果调试的时候无法打断点,代码不匹配,那么有两个原因,一个就是调试的程序和代码不是同一个,要么是运行目录和程序不对,要么是拷贝程序到了另外一个地方,另一个比较难想到,就是如果你的函数没有被调用过,那么也是无法打断点的
14
如果程序直接崩溃,显示的界面是关闭,联机调试关闭,没有显示终止,重试,不能产生dump文件,问题原因就是内存问题,内存越界,访问空指针,野指针等
目前碰到的问题是memcpy的时候,拷贝越界
15
error C3646: unknown override specifier
循环引用
在分离式编译中,我们往往习惯将不同的类或者函数分别写在不同的函数中,提高工作效率。但如果在使用时出现两个类分别在两个不同的文件中编写,并且相互引用,则会出现循环引用,引发此错误。
举例:tire.h/tire.cpp和auto.h/auto.cpp 在tire.h中include auto.h,并定义了一个auto的object,然后在auto.h中又include了tire.h
解决方案:在报错的那个.h文件的类定义前加上class声明调用的类(即class 类)。
语法错误
此问题大多因为粗心而导致,比如在某个成员函数中把分号;写成了中文分号;,将会出现此类错误。
解决方案:修改分号
类的顺序错误
如果一个类的成员中包含另一个类,则被包含的类的声明一定要在包含的类之前。
举例:
class Auto {
Tire tire;
}
class Tire {
int weight;
}
// This will cause error C3656
解决方法:调整类的位置。
16
linux表编译程序的时候希望一些引入的非系统的头文件路径可以直接使用,那么可以把路径添加到这三个变量:C_INCLUDE_PATH
CPLUS_INCLUDE_PATH
CPATH
- C_INCLUDE_PATH C语言有效
- CPLUS_INCLUDE_PATH C++有效
- CPATH C C++都有效
17
下面3个是gcc的宏
// 表明函数有可能在当前文件定义,也有可能在其他文件定义,如果在当前文件定义就用当前文件的;如果没有就在其他文件找
__attribute__((__weak__))
// 告诉编译器,当前函数变量等会用到,不要优化掉
__attribute__((used))
// 告诉编译器,当前函数变量等可能没有用,不要报告没有使用的警告
__attribute__((__unused__))