C/C++/MFC 编译运行错误解决方法收集error

 
一、error C2065: “IDD_DIALOG1” : 未声明的标识符

编译时提示error C2065: “IDD_DIALOG1” : 未声明的标识符html

错误的可能缘由及解决方法以下:
  
1.出错文件中没有包含资源文件ID声明的resource.h文件。在出错文件中加入#include “resource.h”语句。ios

2.工程附件包含目录的路径下没有resource.h文件。修改路径便可。c++

3.工程所在文件夹下存在resource.h文件,但其中没有资源ID的定义, 致使真正的resource.h没有包含进去,删除之。一个解决方案里面有多个工程,可能会把全部资源ID的声明放到一个文件中。在各个工程中实现对话框 功能的文件中,只需包含该文件便可。可是,当新增某个资源之后,工程中会自动生成一个resource.h(不知道为何会这样),而不是在已有的 resource.h文件中添加ID的定义。因为工程编译的时候先从本地搜索头文件,会包含了自动生成的头文件,因而出现了上述错误。程序员

注意:若是是智能设备程序出现此错误,应该确保resourceppc.h和Resourceppc.h中都有相同的宏定义#define IDD_DIALOG1 XXX,而且在dialog.cpp中包含资源头文件resourceppc.h面试

==============================================================
redis

二、error C2471: 没法更新程序数据库 ,fatal error C1083: 没法打开程序数据库文件数据库

error C2471: 没法更新程序数据库“c:documents and settings.......debugvc90.pdb”

fatal error C1083: 没法打开程序数据库文件:“c:documents and settings........debugvc90.pdb”: No such file or directory ....编程

解决方法:windows

修改一下设置,就能够解决C2471:
CC++ | General | Debug Information format | C7 Compatible (/Z7)
CC++ | Code Generation | Enable String Pooling | Yes (/GF)
Linker | General Debug Info | Yes (/DEBUG)app

或者把在debug文件夹下的.pdb文件给删除了,f5一下就好了

================================================================

三、error没法打开预编译头文件的解决方法及预编译头原理

1。用VC.NET编辑程序,按Ctrl+F7,出现下列错误:
fatal error C1083: 没法打开预编译头文件:“Debug/UGFace.pch”: No such file or directory
解决方法:修改:项目->属性->C/C++ ->预编译头->不使用预编译头 便可。


2。学用Visual C++ 6.0的第一个例程就让我出了错.用向导生成第一个基于对话框的Project以后,当我按照书上的源程序一个字一个字地输进去以后,始终有一个错误:
fatal error C1010: unexpected end of file while looking for precompiled header directive.找了无数次以后,我决定把向导生成的包括头文件的语句:include"StdAfx.h"保留(而这以前我是把它删掉了的,由于书 上的例子没有这句.)咦,这下就对了.这是为何呢?我百思不得其解。
来 到个人VC源代码目录,我注意到每一个Project下面的DEBUG文件夹都特别大,并且一个扩展名为 .pch的文件占去了绝大部分,我删掉之好像对程序编译运行没有什么影响。因而抱着对.pch文件的好奇,我在网上搜到了我疑惑之处的解答。这就是 VC++6.0给咱们带来的:预编译头文件。预编译头文件(通常扩展名为.PCH),是把一个工程中较稳定的代码预先编译好放在一个文件(.PCH)里。 这些预先编译好的代码能够是任何的C/C++代码,甚至能够是inline函数,只是它们在整个工程中是较为稳定的,即在工程开发过程当中不会常常被修改的 代码。
为何须要预编译头文件?
一 言以蔽之:提升编译速度.通常地,编译器以文件为单位编译。若是修改了一工程中的一个文件则全部文件都要从新编译,包括头文件里的全部东西 (eg.Macro宏,Preprocessor预处理),而VC程序中,这些头文件中所包括的东西每每是很是大的,编译之将占很长的时间。但它们又不常 被修改,是较稳定的,为单独的一个小文件而从新编译整个工程的全部文件致使编译效率降低,所以引入了.PCH文件。
如何使用预编译头文件以提升编译速度?
要 使用预编译头文件,必须指定一个头文件(.H),它包含咱们不会常常修改的代码和其余的头文件,而后用这个头文件来生成一个预编译头文件 (.PCH),VC默认的头文件就是StdAfx.h,由于头文件是不能编译的,因此咱们还须要一个.CPP文件来做桥梁,VC默认的文件为 StdAfx.cpp,这个文件里只有一句代码就是:#include "StdAfx.h"。接下来要用它生成.PCH文件,涉及到几个重要的预编译指令:/Yu,/Yc,/Yx,/Fp。简单地说,/Yc是用来生 成.PCH文件的编译开关。
在Project->setting->C/C++的Category里的Precompiled Header,而后在左边的树形视图中选择用来编译生成.PCH文件的.CPP文件(默认即StdAfx.cpp),
你 就能够看到/Yc这个开关,它表示这个文件编译了之后是否生成.PCH文件(可能/Yc的c表示create)。/Fp指令指定生成的.PCH文件的名字 及路径(可能/Fp的p表明path)。/Yu的u即use,工程中只要包括了.H文件的文件都会有这个/Yu指令。若是选择自动 Automatic...的话则原来为/Yc的地方就换成了/Yx指令。若是选择自动,则每次编译时编译器会看之前有没有生成过.PCH文件,有则不现生 成不然就再次编译产生.PCH文件。
注意:
A, 实际上,由Appzard项目向导生成的默认的头文件及CPP文件StdAfx.h和StdAfx.cpp能够是任何名字的.缘由很简单。但若是你要这样 作就要记得修改相应的Project->setting...下的几个预编译指(/Yc,/Yu,/Yx,/Fp)的参数。
B. 在任何一个包括了将要预编译的头文件而使用了.PCH文件的工程文件的开头,必定必需要是在最开头,你要包含那个指定生成.PCH文件的.H文件(通 过.CPP文件包括,默认为StdAfx.cpp),若是没包括将产生我最开头产生的错误.若是不是在最开头包括将产生让你意想不到的莫名其妙错误,如若 不信,盍为试之?
C.预编译文件.PCH生成之很耗时间,并且生成以后它也很占磁盘空间,常在5-6M,注意项目完成以后及时清理无用的.PCH文件以节约磁盘空间。
D.若是丢了或删了.PCH文件而之后要再修改工程文件时,可将指定的/Yc的.CPP文件(默认为StdAfx.cpp)从新编译一次便可再次生成.PCH文件,不用傻傻的按F7或Rebuild All


以 前还碰到过另一种状况:新建一个工程,随便找一个cpp文件,按ctrl+f7系统将会提示:fatal error C1083: 没法打开预编译的头文件:”Debug/xxx.pch”: No such file or directory(其中xxx是工程的名字)这种状况也是同样的缘由,为vc的stdafx.h头文件未编译所致。也能够这样解决:先F7,编译后再 ctrf+f7。

注意:VS智能设备程序(如WM5)预编译头文件为stdafx.h。更改设置在项目->XXXX属性->配置属性->C/C++->预编译头 的右侧第一项。
======================================================================
四、
error:没法执行添加/移除操做,由于代码元素是只读的

vc2005error:没法执行添加/移除操做,由于代码元素是只读的
出现这种现象,多数是由于你的工程所在文件夹的属性设置为了“只读”,你能够关闭解决方案,而后从新打开,就能够了,若是之后不想出现这样的状况,把工程所在的文件夹属性中的“只读”去掉,就能够了。

解决方案:
一、重启VS2005

二、查看.h和.cpp文件的属性,有多是只读的,修改属性后就能够了
三、打开Resource.h文件看看 一看就知道了 有些定义重复了 能够手动改掉 保存 编辑器从新加载

四、把你要添加事件的对话框相应的类文件(*.h和*.cpp)给关了就能够了
五、关闭解决方案,删除.ncb文件从新添加便可

六、实在不行就手动添加消息处理

在BEGIN_MESSAGE_MAP(。。。)
//这里要删掉你原先已经增长过的消息隐射函数
END_MESSAGE_MAP()

================================================================

五、程序运行出现-1.#IND,1.#INF


C/C++程序运行有时候会出现-1.#IND,1.#INF,在调试的时候输出除数为0得出的结果,

INF就是infinite,就是无穷大的意思

IND可能表示很小,不肯定

//////////////////////////////////////////////////////////

使用相似于pow, exp等等函数时常会产生一个无效数字1.#IND00,在VC下能够经过与一个肯定数字比较大小来判断是否产生了无效数字,但这个方法在DEV-CPP下倒是行不通的。

其实解决办法很简单,使用   float.h中一个函数_isnan便可:

int _isnan(double x);  
  
当x是一个无效值(NaN, Not a Number) 时,返回非零值
不然返回0

================================================================

六、LINK : 上一个增量连接没有生成它;正在执行彻底连接

代码

#include"iostream"
using namespace std;
int main()
{
cout<<"123";
return 0;
}
LINK : 没有找到 D:Visual Studio 2008ProjectstestDebugtest.exe 或上一个增量连接没有生成它;正在执行彻底连接

这个不是什么错误,如今的VS2003,2005,2009有增量编译功能,就是若是你的代码改动了,他们是不彻底从新编译整个代码的,而是只编译你所更改的部分。

出现这个提示,
1.你是第一次进行编译,这时固然没有生成过可执行文件,也就没法增量连接了。
2.你上一次编译的时候有错误,没有生成可执行文件。
================================================================
七、
CListCtrl的NM_RCLICK消息编译错误、reinterpret_cast

在对话框中类中添加对CListCtrl控件右键处理的时候出现以下错误:

error C2440: 'reinterpret_cast' : cannot convert from 'NMHDR *' to 'NMITEMACTIVATE' Conversion requires a constructor or user-defined-conversion operator, which can't be used by const_cast or reinterpret_cast

须要把:LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);
; 改成: LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE*>(pNMHDR);
参考:http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339678

================================================================

八、没法解析的外部符号 _WinMain,该符号在函数 ___tmainCRTStartup 中被引用

一,问题描述
MSVCRTD.lib(crtexew.obj) : error LNK2019: 没法解析的外部符号_WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用
Debugjk.exe : fatal error LNK1120: 1 个没法解析的外部命令

error LNK2001: unresolved external symbol_WinMain@16
debug/main.exe:fatal error LNK 1120:1 unresolved externals
error executing link.exe;

二,产生这个问题可能的缘由
产生这个问题的真正缘由是c语言运行时找不到适当的程序入口函数,通常状况下,若是是windows程序,那么WinMain是入口函数,若是是dos控制台程序,那么main是入口函数,而若是入口函数指定不当,很显然c语言运行时找不到配合函数,它就会报告错误。

可能:

1, 你用vc建了一个控制台程序,它的入口函数应该是main, 而你使用了WinMain.

2. 你用vc打开了一个.c/.cpp 文件,而后直接编译这个文件,这个文件中使用了WinMian而不是main做为入口函数。vc这时的默认设置是针对控制台程序的。

3.根本就没有WinMain或Main函数。

三, 解决方法
1.进入project->setting->c/c++, 在category中选择preprocessor,在processor definitions中删除_CONSOLE, 添加_WINDOWS

2.进入project->setting->Link, 在Project options中将 /subsystem:console改成/subsystem:windows.

3.保存设置,Rebuild All.

四,VS2008中的设置

1.菜单中选择 Project->Properties, 弹出Property Pages窗口

2.在左边栏中依次选择:Configuration Properties->C/C++->Preprocessor,而后在右边栏的Preprocessor Definitions对应的项中删除_CONSOLE, 添加_WINDOWS.

3.在左边栏中依次选择:Configuration Properties->Linker->System,而后在右边栏的SubSystem对应的项改成Windows(/SUBSYSTEM:WINDOWS)

4.Rebuild All. Ok ?

================================================================

九、fatal error LNK1112: 模块计算机类型“ARM”与目标计算机类型“X86”冲突

fatal error LNK1112: 模块计算机类型“ARM”与目标计算机类型“X86”冲突

解决方法:连接器 -> 命令行 -> 附加选项, 添加 /MACHINE:ARM /MACHINE:THUMB

 

fatal error LNK1112: 模块计算机类型“THUMB”与目标计算机类型“ARM”冲突

解决方法:

第1种:连接器 -> 命令行 -> 附加选项, 添加 /MACHINE:THUMB

第2种:新建项目时,在"平台"->"选择要添加到当前项目中的 Platform SDK。"中,把"已安装的 SDK"所有添加到"选定的 SDK"

若是是直接使用已经建立好的工程,那么第一种方法就能够解决了,实在不行,就只有采用第二种办法从头解决了 。

 

================================================================

十、error c3872: “0x3000”: 此字符不容许在标识符中使用

例如friend ostream& operator<<(ostream& out,const Chain<T>& x );
出错error c3872: “0x3000”: 此字符不容许在标识符中使用

解决方法:

0x3000是汉语的空格,也就是全角空格,至关于一个汉字,但你又看不见它。

像逗号,有半角(,)和全角(,)之分的,其实空格也有。
0x3000是全角的空格,0x20是半角的空格。

你最好把这个语句的后面空白部分都删除掉,并检查是否有中文标点存在

================================================================

十一、0x????处未处理的异常:0xC0000005

    使用VC编码的时候常常会出现“Test.exe 中的 0x00414030 处未处理的异常: 0xC0000005: 写入位置 0xfeeefeee 时发生访问冲突 。

     出现0xC0000005的缘由通常都是没有分配内存 或者 内存无效 所致,

例如:

#include "stdafx.h"
#include <string>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

string * s = NULL;
s = new string();
delete s;

if (s != NULL)
{
   *s = "TEST"; //这步操做将引发异常。
}

return 0;
}

虽然s已经被delete了,可是s的值并不为NULL,if语句的判断将失效,这是新手常见的一个错误!

为了防止这个错误能够本身定义一个宏来处理delete。

#define _DELETE(obj) if (obj != NULL) {delete obj , obj = NULL;}

使用这个宏能够防止相似错误出现。

 

================================================================

十二、没有找到MFC80UD.DLL,所以这个程序未能启动.从新安装应用程序可能会修复此问题

在vs2005 sp1中文版中,在“解决方案资源管理器”中的项目上右击,选择“属性”,找到“配置属性”中的“连接器”,而后找到“清单文件”,在右边的属性框中,默认“生成清单”项为“是”,选 把“是”改为“否”,运行之,出错,而后再把否改回来,OK

其余:

1)若是不选"系统菜单""关于菜单"就不会有这个问题!
2)若是在"工程属性->配置属性->常规->字符集""使用多字节字符集"也不会出这个问题!
3)好像是删除全部的中间文件,(具体一点说,就是删除."(工程文件)"Debug里的文件和.ncb),"从新生成解决方案文件...",可能能够.
4clean关闭vs,打开rebuild应该就能够了,个人不多遇到。遇到以后这样就解决了。不行就多试几回。
5linker-manifest-file-Generate Manifest: Yes
6Manifest搞的鬼,而后修改项目属性,清单工具中的输入输出把嵌入清单文件选否.而后编译,连接运行,成功

debug---动态使用dll
release---静态使用dll

debug状态下使用,会时不时出这个问题;
release状态下使用,不会出现这个问题。

 

================================================================

1三、没有找到MFC80D.DLL或msvcr80d.dll的解决方法

   解决方案:

在编辑状态下,点项目菜单 -> XXX属性页 -> 配置属性 -> 清单工具,将右面的使用FAT32解决办法选为便可。简单地,其实把程序目录下的Debug目录整个删掉,再让VS所有从新生成文件也能解决这个问题,只是可能再犯。

没有找到MFC80D.DLL的解决方法。问题出如今程 序运行清单上,默认是"嵌入清单",清单文件是"$(IntDir$(TargetFileName).embed.manifest"。调试程序运行 时,不知道为何却定位不到这个文件,咱们若是手动把"程序名.embed.manifest"改成"程序名.manifest",调试程序便可定位到。

其余

方法一:
在C:Program FilesMicrosoft Visual Studio 8VCredi
stDebug_NonRedistx86Microsoft.VC80.DebugCRT 下找到了下列文件:

msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
Microsoft.VC80.DebugCRT.manifest

把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,就能够运行那个程序了。

方法二:
修改编译选项,将/MD或/MDd 改成 /MT或/MTd,这样就实现了对VC运行时库的静态连接,在运行时就再也不须要VC的dll了。

 

================================================================

1四、fatal error LNK1181: 没法打开输入文件“..filename.lib”

连接器未能找到 filename,由于该文件不存在或未找到路径。

如下常见缘由可致使错误 LNK1181:

filename 在连接器行上做为附加依赖项被引用,但该文件不存在。

缺乏用于指定包含 filename 的目录的 /LIBPATH 语句。

若要解决上面的问题,请确保连接器行上引用的任何文件在系统中存在。 另外,请确保对于包含依赖于连接器的文件的每一个目录都存在 /LIBPATH 语句。

致使 LNK1181 的另外一可能缘由是具备嵌入空格的长文件名没有括在引号内。 在这种状况下,连接器仅将文件名识别到第一个空格处,而后假定文件的扩展名为 .obj。 此状况的解决方案是将长文件名(路径和文件名)括在引号内。

 

================================================================

1五、没有找到MFC80D.DLL,所以这个程序未能启动.从新安装应用程序可能会修复此问题

解决方法:删除程序目录下Debug文件夹和Release文件夹,而后从新编译执行。

===网上其余方法=============

方法一:
没 有找到MFC80D.DLL的解决方法。问题出如今程序运行清单上,默认是"嵌入清单",清单文件是 "$(IntDir$(TargetFileName).embed.manifest"。调试程序运行时,不知道为何却定位不到这个文件,咱们若是 手动把"程序名.embed.manifest"改成"程序名.manifest",调试程序便可定位到。

方法二:
在C:Program FilesMicrosoft Visual Studio 8VCredistDebug_NonRedistx86Microsoft.VC80.DebugCRT 下找到了下列文件:
msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
Microsoft.VC80.DebugCRT.manifest
把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,就能够运行那个程序了。

方法三:
修改编译选项,将/MD或/MDd 改成 /MT或/MTd,这样就实现了对VC运行时库的静态连接,在运行时就再也不须要VC的dll了。

 

================================================================

1六、mspdb80.dll没法找到的解决方法

在cmd中键入cl执行编译时会出现mspdb80.dll没法找到的状况,是由于VCBin下没有“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件,解决的方法:
1>直接从Microsoft Visual Studio 8Common7IDE下复制这四个文件到Microsoft Visual Studio 8VCBin下便可解决
2> 添加系统变量(Path),这样:个人电脑->属性->高级->环境变量->系统变量,在path中添加C:Program FilesMicrosoft Visual Studio 8Common7IDE;,注意结尾最后用“;”隔开!
这样在用cl编译就不会出现mspdb80.dll文件找不到的错误了。

 

================================================================

1七、error LNK2019: 没法解析的外部符号....该符号在函数 ...中被引用

这种状况通常都是函数只找到声明但没有实现,或者是少了什么连接库,你能够试试把那两个.h和.c文件直接加入工程中再试试。

有一个解决方案,有两个工程A,B。工程B中定义了一个类,在工程A的demo.cpp中引用该类,可是若是是

#include "XX,h",则会出现“error LNK2019: 没法解析的外部符号”

若是是#include "XX.cpp",则能够顺利编译经过。

想来是由于引用 .h 文件致使找不到.cpp中的定义,而引用.cpp能够经过.cpp找到.h(.cpp有对.h的include)

可是若是同在工程B下面,则#include "XX,h"也是正确的,它会自动关联到同名的(反正是对应的).cpp文件。

在不一样工程中应该如何引用呢?

看见一种缘由分析,以下:

现场状况:

funcname 在文件file.cpp/h中定义实现

void funcname(void) {;}

filecall.c文件内呼叫funcname()函数。

出现上面状况。

症因:因c/c++混合编程, c文件内函数没法呼叫c++文件内函数。

解决,或者将c文件名改成.cpp,或者将c++文件名改成.c

上面的解决采用将 file.cpp 改名为file.c便可。

1.
在 Visual C++ .NET 2003 中,若是使用了 /clr 而未将 CRT 连接到可执行文件,将生成此错误。任何由编译器在未使用 /clr:initialAppDomain 时生成的对象代码都包含对 _check_commonlanguageruntime_version 函数的引用,该函数在 C 运行时库 (CRT) 中定义。若是应用程序在运行库的版本 1 上运行,该函数将会生成一个错误信息。当前编译器生成的代码与运行库的版本 1 不兼容。所以,若是在 Visual C++ .NET 2003 中编译时不使用 CRT,则应在代码中包含 _check_commonlanguageruntime_version 函数的定义。做为使用 _check_commonlanguageruntime_version 函数的替代方法,您能够与 nochkclr.obj 连接。nochkclr.obj 包含该函数的一个空版本,当您在运行库的版本 1 上运行应用程序时,nochkclr.obj 不生成错误信息。若要使用当前编译器版本生成应用程序以在运行库的之前版本上运行,应使用 /clr:InitialAppDomain。
若要 生成一个纯 MSIL 可执行文件(不与 CRT 连接),则必须在项目中定义该函数,而不能使用 nochkclr.obj(.obj 是本机代码)。有关可验证代码的更多信息,请参见产生可验证的 C++ 托管扩展组件。有关从托管 C++ 项目建立纯 MSIL 输出文件的更多信息,请参见将 C++ 托管扩展项目从混合模式转换成纯 IL。

2.
请看下面的示例:
extern int i;
extern void g();
void f()
{
i++;
g();
}
int main()
{
}
若是在生成中包含的某个文件中没有定义 i 和 g,连接器将生成 LNK2019。能够添加这些定义,方法是将包含这些定义的源代码文件包括为编译的一部分。或者能够将包含这些定义的 .obj 或 .lib 文件传递给连接器。


3.
对于从早期版本升级到当前版本的 C++ 项目,若是定义了 __UNICODE 而且入口点为 WinMain,须要将入口点函数的名称更改成 _tWinMain 或 _tmain。

4.
符号声明包含拼写错误,以至于符号声明与符号定义不一样。

5.
使用了一个函数,但其参数的类型或数量与函数定义不匹配。
函数声明使用和函数定义使用中的调用约定(__cdecl、__stdcall 或 __fastcall)不一样。

6.
符号定义在编译为 C 程序的文件中,而符号是在 C++ 文件中不带 extern "C" 修饰符声明的。在此状况下,请修改声明,例如不是使用:
extern int i;
extern void g();
而使用:

extern "C" int i;
extern "C" void g();
一样,若是在将由 C 程序使用的 C++ 文件中定义符号,请在定义中使用 extern "C"。


7.
符号定义为静态,但稍后在文件外部被引用。
没有定义静态类成员。例如,应单独定义下面类声明中的成员变量 si:
#include <stdio.h>
struct X {
static int si;
};

// int X::si = 0; // uncomment this line to resolve

void main()
{
    X *px = new X[2];
    printf("n%d",px[0].si); // LNK2019
}

8.
也可能因为为 Visual Studio .NET 2003 进行的一致性工做生成此错误:模板友元和专用化。在 Visual Studio .NET 2003 中,必须定义声明新的非模板函数的友元声明。
要使代码在 Visual C++ 的 Visual Studio .NET 2003 和 Visual Studio .NET 版本中均有效,请显式指定友元函数的模板参数列表。
// LNK2019.cpp
// LNK2019 expected
template<class T>
void f(T)
{
}

template<class T>
struct S
{
    friend void f(T);
    // Try the folowing line instead:
    // friend void f<T>(T);
};

int main()
{
    S<int> s;
    f(1); // unresolved external
}


/VERBOSE 连接器选项帮助您查看连接器引用的文件。DUMPBIN 实用工具的 /EXPORT 和 /SYMBOLS 选项还能够帮助您查看 dll 和对象/库文件中定义的符号。

-------------------------------------

例如“error LNK2019: 没法解析的外部符号_imp__SetupDiGetDeviceInterfaceDetailW@24
error LNK2001: 没法解析的外部符号“private: static struct _OVERLAPPED CUsbCom::g_WriteOverlapped”

应该是工程设置的问题 没有链接相应的lib库或者是所用到的函数没定义(这个定义是在别的类里面的)

当出现error LNK2001: 没法解析的外部符号 _print_interface   log.obj      可在log.c里搜print_interface(无前面_),找到此函数,看有无定义学习VC++时常常会遇到连接错误LNK2001,该错误很是讨 厌,由于对于 编程者来讲,最好改的错误莫过于编译错误,而通常说来发生链接错误时,编译都已经过。产生链接错误的缘由很是多,尤为LNK2001错误,经常令人不 明其因此然。若是不深刻地学习和理解VC++,要想改正链接错误LNK2001非 常困难。
初学者在学习VC++的过程当中,遇到的LNK2001错误的错误消息主要为:
unresolved external symbol “symbol”(不肯定的外部“符号”)。 若是链接程序不能在全部的库和目标文件内找到所引用的函数、变量或 标签,将产生此错误消息。通常来讲,发生错误的缘由有两个:一是所引用 的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不一样版本的链接库。
如下是可能产生LNK2001错误的缘由:
一.因为编码错误致使的LNK2001。
1.不相匹配的程序代码或模块定义(.DEF)文件能致使LNK2001。例如, 若是在C++ 源文件内声明了一变量“var1”,却试图在另外一文件内以变量 “VAR1”访问该变量,将发生该错误。
2.若是使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将致使LNK2001错误。
3.调用函数时若是所用的参数类型同函数声明时的类型不符将会产生 LNK2001。
4.试图从基类的构造函数或析构函数中调用虚拟函数时将会致使LNK2001。
5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。
静态函数和静态变量具备相同的使用范围限制。当试图从文件外部访问任何没有在该文件内声明的静态变量时将致使编译错误或LNK2001。函数内声明的变量(局部变量) 只能在该函数的范围内使用。
C++ 的全局常量只有静态链接性能。这不一样于C,若是试图在C++的 多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是须要时在头文件中加入该常量的初始化代码,并在.CPP文件中包含该头文件;另外一种 方法是使用时给该变量赋以常数。
二.因为编译和连接的设置而形成的LNK2001
1.若是编译时使用的是/NOD(/NODEFAULTLIB)选项,程序所须要的运行库和MFC库在链接时由编译器写入目标文件模块, 但除非在文件中明确包含 这些库名,不然这些库不会被连接进工程文件。在这种状况下使用/NOD将导 致错误LNK2001。
2.若是没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将获得“unresolved external on _WinMain@16”的LNK2001错误信息。
3.使用/MD选项编译时,既然全部的运行库都被保留在动态连接库以内,源文件中对“func”的引用,在目标文件里即对“__imp__func” 的引用。
若是试图使用静态库LIBC.LIB或LIBCMT.LIB进行链接,将在__imp__func上发 生LNK2001;若是不使用/MD选项编译,在使用MSVCxx.LIB链接时也会发生LNK2001。
4.使用/ML选项编译时,如用LIBCMT.LIB连接会在_errno上发生LNK2001。
5.当编译调试版的应用程序时,若是采用发行版模态库进行链接也会产生LNK2001;一样,使用调试版模态库链接发行版应用程序时也会产生相同的 问题。
6.不一样版本的库和编译器的混合使用也能产生问题,由于新版的库里可 能包含早先的版本没有的符号和说明。
7.在不一样的模块使用内联和非内联的编译选项可以致使LNK2001。若是建立C++库时打开了函数内联(/Ob1或/Ob2),可是在描述该函数的相应 头文件里却关闭了函数内联(没有inline关键字),这时将获得该错误信息。 为避免该问题的发生,应该在相应的头文件中用inline关键字标志内联函数。
8.不正确的/SUBSYSTEM或/ENTRY设置也能致使LNK2001。 其实,产生LNK2001的缘由还有不少,以上的缘由只是一部分而已,对初 学者来讲这些就够理解一阵子了。可是,分析错误缘由的目的是为了不错 误的发生。LNK2001错误虽然比较困难,可是只要注意到了上述问题,仍是可以避免和予以解决的。

既然编译经过了,就说明了没有语法错误,不用在代码中死抠语法了。从错误中提示中找缘由吧。

通常问题出在

(1)XXX.lib头文件,这个要包含(否则编译也不能经过)

(2)须要XXX.lib或XXX.dll库。手动添加,项目->属性->配置属性->连接器->输入 而后在附件依赖项添加XXX.lib,再生成第一个没法解析的外部符号错误消失了。

 

================================================================

1八、Visual Studio 2005不能进行调试,错误126: 找不到指定的模块

Visual Studio 2005一直不能进行调试,查看出错的缘由,是由于Terminal Services服务不能正确启动。在【服务】里尝试启动Termial Services服务时,一直提示【 错误126: 找不到指定的模块 】的错。上网搜索了一下,发现了这样的信息:
错误126:找不到指定的模块 1. 故障现象尝试在“服务”管理单元窗口手动启动服务时,系统提示“错误126:找不到指定的模块”(Error 126: The specified module could not be found.), 2.缘由分析该故障一般在由svchost服务宿主进程所启动的服务上发生。这一类的Windows服务,实际上是以dll模块的形式插入某个 svchost进程。若是该dll文件被破坏,或者注册表的相关键值被篡改,均可能致使问题。这类服务所对应的Dll文件,是由HKLMSYSTEM CurrentControlSetServicesServiceNameParameters注册表项下的ServiceDll键值所定义的 (此处的ServiceName是指服务名),若是该注册表键值出错,或者对应的Dll文件被破坏,就会致使这个问题。

经过查看注册表文件,发现【Terminal Services】服务对应与 %SystemRoot%System32termsrv.dll 文件。查看个人本地文件,不知道什么时候这个文件名称被修改了termsrv.dl_。

修改成termsrv.dll后,再启动【Terminal Services】服务,正常启动,调试Visual Studio 2005项目,一切OK!

 

================================================================

1九、MFC 对话框不能显示中文

在资源视图中右击对话框ID,选属性,修改语言设置

================================================================

20、error C2248: 'CObject::operator =' : cannot access private member declared in class

1>e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafxtempl.h(776) : error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
1>        e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafx.h(562) : see declaration of 'CObject::operator ='
1>        e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafx.h(532) : see declaration of 'CObject'
1>        This diagnostic occurred in the compiler generated function 'CList<TYPE,ARG_TYPE> &CList<TYPE,ARG_TYPE>::operator =(const CList<TYPE,ARG_TYPE> &)'
1>        with
1>        [
1>            TYPE=CProgram,
1>            ARG_TYPE=CProgram &
1>        ]

上面这段编译器报警是否是有似曾相识的感受?想必不少人在用VC2005以及以后的版本的VC编译器时看到过这个东西,在google查一下error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'你会发现不少人碰到相似的问题。一位叫“中国民工”的blog中说明了引起这一问题的的缘由,请参见http://www.cppblog.com/hlong/archive/2007/11/20/37015.html

根据民工兄的解释,因为咱们的类中定义了CArray类型的成员,而CArray<A, A&>类的operator=是private类型(它继承自CObject::operator=,且被定义为private类型)。并给出了解决之道:若是咱们的类/结构体中有CArray(或CList等其余的派生自CObject类)的成员变量,咱们最好添加上一个public类型的operator=运算赋重载函数;

问题虽然是解决了,可是彷佛仍是没弄明白产生问题的根本缘由:既然问题是因为CArray没有定义Operator=操做从而致使须要调用基类CObject中的私有Operator= 操做而引发的,那么为何微软要将CObject的Operator=操做定义成私有呢?或者说为何CObject在实际上并无对Operator= 和拷贝构造函数作任何实质性的定义的状况下要去定义这两个函数,而且还将他们定义为private。。惟一的解释就是微软不但愿继承自CObject的类 使用默认的Operator=操做,或者说微软不但愿使用了CArray或者CList或者CMap的Collections模板类的类使用默认的Operator=操做。答案的确是如此,不只如此,对于默认的拷贝构造函数结论也是同样(可能有些人碰到到一样的编译器报错,不过是针对拷贝构造函数的,后面我会解释引起这两种类型的报错的真正缘由)。

要想搞清楚这个问 题,就先要了解C++编译器生成的默认函数——这些咱们平时一直在使用却不多关心的幕后工做者究竟是怎样工做的。当咱们建立一个C++变量,为一个变量赋 值,或者调用一个C++函数,或者对一个C++变量进行取地址&操做时,这些都是一些基本操做,咱们老是能获得咱们想要的结果(至少看起来是这 样)由于这些都是C++的语义,而负责实现这些语义的是C++编译器。

编译器又是如何实 现这些语义的呢,好比当你构造一个C++变量时,编译器会检查你有没有为这个变量的类型建立一个构造函数,若是没有,编译器会本身帮你生成一个默认的构造 函数,从而实现了一个C++变量的构造;相似的,在用户执行其余一些诸如赋值操做,拷贝构造,取地址等基本操做时,编译器遵循一样的原则,即在用户未定义 相应的操做状况下自动生成一个默认的操做;正由于如此,甚至不少程序员并不知道它们的存在(我记得几年前我去一家公司面试的时候,就被问及过这样一个问题:C++类的默认函数有几个,分别是什么,,其实这是一个蛮深入的问题),即便知道它们,也会以为在不须要咱们付出任何关心的状况下,这些操做都是理所应当应该是正确的,可是事实并不是老是如此。

Effective C++在条款45也对这几个函数进行了比较详细的分析;其中构造函数和析构函数其实就是一个空函数,什么也不作,因此当咱们用VC也好或者其余的C++编 译器建立一个空类也好,编译器都会为咱们的类事先定义一个构造和析构函数,就是为了避免让咱们去使用默认的构造和析构函数。因此通常状况下咱们不多会忽视这 两个函数的存在,可是另外3个很重要的函数:拷贝构造和赋值操做符,以及取地址操做符就很容易被忽视掉,由于咱们不多去实现这3个操做,大部分都是使用的 编译器提供的默认的实现。

对于默认赋值操做符和拷贝构造函数的默认实现,Effective C++上的解释是:官 方的规则是:缺省拷贝构造函数(赋值运算符)对类的非静态数据成员进行 "以成员为单位的" 逐一拷贝构造(赋值)。即,若是m是类C中类型为T的非静态数据成员,而且C没有声明拷贝构造函数(赋值运算符),m将会经过类型T的拷贝构造函数(赋值 运算符)被拷贝构造(赋值)---- 若是T有拷贝构造函数(赋值运算符)的话。若是没有,规则递归应用到m的数据成员,直至找到一个拷贝构造函数(赋值运算符)或固定类型(例 如,int,double,指针,等)为止。默认状况下,固定类型的对象拷贝构造(赋值)时是从源对象到目标对象的 "逐位" 拷贝。对于从别的类继承而来的类来讲,这条规则适用于继承层次结构中的每一层,因此,用户自定义的构造函数和赋值运算符不管在哪一层被声明,都会被调用。

另一个很重要的概念是:当且仅当相应的操做被定义时,编译器才为操做变量所属的类型生成对应的默认操做;也就是说,若是代码中没有出现相应的操做,编译器什么也不会作。

再回到咱们一开始民工兄的例子中,假设咱们的类C中定义了一个CArray类型的成员变量,而且C中没有显示的定义operator=操做(这就意味着编译器可能须要为C自动生成一个默认的operator=操做)根据上面的说法,当且仅当C的实例被赋值时编译器才会生 成默认的operator=操做,而编译器报警告诉咱们,编译器在生成operator=操做时遇到了障碍,这个障碍就是:C的CArray成员具备一个 赋值运算符定义,可是该定义是私有的(其实是CArray继承自CObject的operator=定义)。。咱们看一下民工兄的例子的源码:

3struct A
4
{
5
     int a;
6
};
7

8struct B
9
{
10      CArray<A, A&> b;

24};
25

26 typedef CArray<B, B&> C;
27

28void test()
29
{
30
     B b;
31
     C c;
32
     c.Add(b);
33 }

从这段代码中能够看出,test中对B的实例b并无作任何赋值的操做,为何编译器会去实现B的默认operator=操做呢?

问题就处在CArray::Add()的函数签名身上,Add函数的源码以下

template<class TYPE, class ARG_TYPE>
AFX_INLINE INT_PTR CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
{ INT_PTR nIndex = m_nSize;
   SetAtGrow(nIndex, newElement);

   return nIndex; }

可见,形参newElement的类型是ARG_TYPE,ARG_TYPE其实就是TYPE的引用,在这里就是B的引用;答案彷佛明了了:

由于Add函数的签名要求输入参数的类型为B&,因此当编译器编译语句:c.Add(b); 时会自动将b强制转换成B的引用,即将这条语句编译成:B& d = b; c.Add(d); 赋值操做就这样出现了!

为了验证这个想法,能够作另外一个测试,调用一个传值的函数,这样就不须要作“B& d = b;”的转换了,那么就应该不会有问题了。

很不幸,实际上编译器会报一样的错误,只是如今不是operator=而是拷贝构造函数。

原 因很简单,由于对于传值的方式,实际上就是“经过值来传递一个对象”,而这又是由这个对象的类的拷贝构造函数定义的。也就是说当经过传值的方式调用一个子 程序时,最终是编译器经过调用拷贝构造函数来实现的。因此问题是同样的,由于类型B没有定义本身的拷贝构造函数,因而编译器试图生成一个默认的,但它一样 遇到了障碍,由于CArray的拷贝构造也是private的(一样继承于CObject)。

至此,咱们对于这个问题有了一个比较全面的认识,其实问题的本质在于:不管是默认的operator=仍是默认的拷贝构造也好都是有其致命的缺陷的,正如Effective C++条款11中所描述的,当这些默认的实如今遇到须要动态分配内存的类的时候就会出现问题,也就是所谓的深拷贝问题。而Collections模板类就是典型的不能使用默认operator=和默认的拷贝构造的例子。

因此当咱们自定义的类中包含Collections模板类的成员时咱们就无法再偷懒使用编译器自动生成的operator=和的拷贝构造了,而必须本身动手实现,这也是微软想提醒咱们的一个事实。


================================================================
2一、
error : WINDOWS.H already included. MFC apps must not #include <windows.h>

在windows console下编译 的时候遇到这个问题的

#include <afx.h>//由于要用到CString因此要包含这个头文件
#include <iostream>

using namespace std;

后来把头文件包含位置换了下 编译经过
#include <afx.h>//由于要用到CString因此要包含这个头文件

#include <iostream>
using namespace std;

error是由于将#include<stdafx.h>放在其它#include的后面了。
这个文件应该放在最前面。
 
一、error C2065: “IDD_DIALOG1” : 未声明的标识符

编译时提示error C2065: “IDD_DIALOG1” : 未声明的标识符

错误的可能缘由及解决方法以下:
  
1.出错文件中没有包含资源文件ID声明的resource.h文件。在出错文件中加入#include “resource.h”语句。

2.工程附件包含目录的路径下没有resource.h文件。修改路径便可。

3.工程所在文件夹下存在resource.h文件,但其中没有资源ID的定义, 致使真正的resource.h没有包含进去,删除之。一个解决方案里面有多个工程,可能会把全部资源ID的声明放到一个文件中。在各个工程中实现对话框 功能的文件中,只需包含该文件便可。可是,当新增某个资源之后,工程中会自动生成一个resource.h(不知道为何会这样),而不是在已有的 resource.h文件中添加ID的定义。因为工程编译的时候先从本地搜索头文件,会包含了自动生成的头文件,因而出现了上述错误。

注意:若是是智能设备程序出现此错误,应该确保resourceppc.h和Resourceppc.h中都有相同的宏定义#define IDD_DIALOG1 XXX,而且在dialog.cpp中包含资源头文件resourceppc.h

==============================================================

二、error C2471: 没法更新程序数据库 ,fatal error C1083: 没法打开程序数据库文件

error C2471: 没法更新程序数据库“c:documents and settings.......debugvc90.pdb”

fatal error C1083: 没法打开程序数据库文件:“c:documents and settings........debugvc90.pdb”: No such file or directory ....

解决方法:

修改一下设置,就能够解决C2471:
CC++ | General | Debug Information format | C7 Compatible (/Z7)
CC++ | Code Generation | Enable String Pooling | Yes (/GF)
Linker | General Debug Info | Yes (/DEBUG)

或者把在debug文件夹下的.pdb文件给删除了,f5一下就好了

================================================================

三、error没法打开预编译头文件的解决方法及预编译头原理

1。用VC.NET编辑程序,按Ctrl+F7,出现下列错误:
fatal error C1083: 没法打开预编译头文件:“Debug/UGFace.pch”: No such file or directory
解决方法:修改:项目->属性->C/C++ ->预编译头->不使用预编译头 便可。


2。学用Visual C++ 6.0的第一个例程就让我出了错.用向导生成第一个基于对话框的Project以后,当我按照书上的源程序一个字一个字地输进去以后,始终有一个错误:
fatal error C1010: unexpected end of file while looking for precompiled header directive.找了无数次以后,我决定把向导生成的包括头文件的语句:include"StdAfx.h"保留(而这以前我是把它删掉了的,由于书 上的例子没有这句.)咦,这下就对了.这是为何呢?我百思不得其解。
来 到个人VC源代码目录,我注意到每一个Project下面的DEBUG文件夹都特别大,并且一个扩展名为 .pch的文件占去了绝大部分,我删掉之好像对程序编译运行没有什么影响。因而抱着对.pch文件的好奇,我在网上搜到了我疑惑之处的解答。这就是 VC++6.0给咱们带来的:预编译头文件。预编译头文件(通常扩展名为.PCH),是把一个工程中较稳定的代码预先编译好放在一个文件(.PCH)里。 这些预先编译好的代码能够是任何的C/C++代码,甚至能够是inline函数,只是它们在整个工程中是较为稳定的,即在工程开发过程当中不会常常被修改的 代码。
为何须要预编译头文件?
一 言以蔽之:提升编译速度.通常地,编译器以文件为单位编译。若是修改了一工程中的一个文件则全部文件都要从新编译,包括头文件里的全部东西 (eg.Macro宏,Preprocessor预处理),而VC程序中,这些头文件中所包括的东西每每是很是大的,编译之将占很长的时间。但它们又不常 被修改,是较稳定的,为单独的一个小文件而从新编译整个工程的全部文件致使编译效率降低,所以引入了.PCH文件。
如何使用预编译头文件以提升编译速度?
要 使用预编译头文件,必须指定一个头文件(.H),它包含咱们不会常常修改的代码和其余的头文件,而后用这个头文件来生成一个预编译头文件 (.PCH),VC默认的头文件就是StdAfx.h,由于头文件是不能编译的,因此咱们还须要一个.CPP文件来做桥梁,VC默认的文件为 StdAfx.cpp,这个文件里只有一句代码就是:#include "StdAfx.h"。接下来要用它生成.PCH文件,涉及到几个重要的预编译指令:/Yu,/Yc,/Yx,/Fp。简单地说,/Yc是用来生 成.PCH文件的编译开关。
在Project->setting->C/C++的Category里的Precompiled Header,而后在左边的树形视图中选择用来编译生成.PCH文件的.CPP文件(默认即StdAfx.cpp),
你 就能够看到/Yc这个开关,它表示这个文件编译了之后是否生成.PCH文件(可能/Yc的c表示create)。/Fp指令指定生成的.PCH文件的名字 及路径(可能/Fp的p表明path)。/Yu的u即use,工程中只要包括了.H文件的文件都会有这个/Yu指令。若是选择自动 Automatic...的话则原来为/Yc的地方就换成了/Yx指令。若是选择自动,则每次编译时编译器会看之前有没有生成过.PCH文件,有则不现生 成不然就再次编译产生.PCH文件。
注意:
A, 实际上,由Appzard项目向导生成的默认的头文件及CPP文件StdAfx.h和StdAfx.cpp能够是任何名字的.缘由很简单。但若是你要这样 作就要记得修改相应的Project->setting...下的几个预编译指(/Yc,/Yu,/Yx,/Fp)的参数。
B. 在任何一个包括了将要预编译的头文件而使用了.PCH文件的工程文件的开头,必定必需要是在最开头,你要包含那个指定生成.PCH文件的.H文件(通 过.CPP文件包括,默认为StdAfx.cpp),若是没包括将产生我最开头产生的错误.若是不是在最开头包括将产生让你意想不到的莫名其妙错误,如若 不信,盍为试之?
C.预编译文件.PCH生成之很耗时间,并且生成以后它也很占磁盘空间,常在5-6M,注意项目完成以后及时清理无用的.PCH文件以节约磁盘空间。
D.若是丢了或删了.PCH文件而之后要再修改工程文件时,可将指定的/Yc的.CPP文件(默认为StdAfx.cpp)从新编译一次便可再次生成.PCH文件,不用傻傻的按F7或Rebuild All


以 前还碰到过另一种状况:新建一个工程,随便找一个cpp文件,按ctrl+f7系统将会提示:fatal error C1083: 没法打开预编译的头文件:”Debug/xxx.pch”: No such file or directory(其中xxx是工程的名字)这种状况也是同样的缘由,为vc的stdafx.h头文件未编译所致。也能够这样解决:先F7,编译后再 ctrf+f7。

注意:VS智能设备程序(如WM5)预编译头文件为stdafx.h。更改设置在项目->XXXX属性->配置属性->C/C++->预编译头 的右侧第一项。
======================================================================
四、
error:没法执行添加/移除操做,由于代码元素是只读的

vc2005error:没法执行添加/移除操做,由于代码元素是只读的
出现这种现象,多数是由于你的工程所在文件夹的属性设置为了“只读”,你能够关闭解决方案,而后从新打开,就能够了,若是之后不想出现这样的状况,把工程所在的文件夹属性中的“只读”去掉,就能够了。

解决方案:
一、重启VS2005

二、查看.h和.cpp文件的属性,有多是只读的,修改属性后就能够了
三、打开Resource.h文件看看 一看就知道了 有些定义重复了 能够手动改掉 保存 编辑器从新加载

四、把你要添加事件的对话框相应的类文件(*.h和*.cpp)给关了就能够了
五、关闭解决方案,删除.ncb文件从新添加便可

六、实在不行就手动添加消息处理

在BEGIN_MESSAGE_MAP(。。。)
//这里要删掉你原先已经增长过的消息隐射函数
END_MESSAGE_MAP()

================================================================

五、程序运行出现-1.#IND,1.#INF


C/C++程序运行有时候会出现-1.#IND,1.#INF,在调试的时候输出除数为0得出的结果,

INF就是infinite,就是无穷大的意思

IND可能表示很小,不肯定

//////////////////////////////////////////////////////////

使用相似于pow, exp等等函数时常会产生一个无效数字1.#IND00,在VC下能够经过与一个肯定数字比较大小来判断是否产生了无效数字,但这个方法在DEV-CPP下倒是行不通的。

其实解决办法很简单,使用   float.h中一个函数_isnan便可:

int _isnan(double x);  
  
当x是一个无效值(NaN, Not a Number) 时,返回非零值
不然返回0

================================================================

六、LINK : 上一个增量连接没有生成它;正在执行彻底连接

代码

#include"iostream"
using namespace std;
int main()
{
cout<<"123";
return 0;
}
LINK : 没有找到 D:Visual Studio 2008ProjectstestDebugtest.exe 或上一个增量连接没有生成它;正在执行彻底连接

这个不是什么错误,如今的VS2003,2005,2009有增量编译功能,就是若是你的代码改动了,他们是不彻底从新编译整个代码的,而是只编译你所更改的部分。

出现这个提示,
1.你是第一次进行编译,这时固然没有生成过可执行文件,也就没法增量连接了。
2.你上一次编译的时候有错误,没有生成可执行文件。
================================================================
七、
CListCtrl的NM_RCLICK消息编译错误、reinterpret_cast

在对话框中类中添加对CListCtrl控件右键处理的时候出现以下错误:

error C2440: 'reinterpret_cast' : cannot convert from 'NMHDR *' to 'NMITEMACTIVATE' Conversion requires a constructor or user-defined-conversion operator, which can't be used by const_cast or reinterpret_cast

须要把:LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);
; 改成: LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE*>(pNMHDR);
参考:http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339678

================================================================

八、没法解析的外部符号 _WinMain,该符号在函数 ___tmainCRTStartup 中被引用

一,问题描述
MSVCRTD.lib(crtexew.obj) : error LNK2019: 没法解析的外部符号_WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用
Debugjk.exe : fatal error LNK1120: 1 个没法解析的外部命令

error LNK2001: unresolved external symbol_WinMain@16
debug/main.exe:fatal error LNK 1120:1 unresolved externals
error executing link.exe;

二,产生这个问题可能的缘由
产生这个问题的真正缘由是c语言运行时找不到适当的程序入口函数,通常状况下,若是是windows程序,那么WinMain是入口函数,若是是dos控制台程序,那么main是入口函数,而若是入口函数指定不当,很显然c语言运行时找不到配合函数,它就会报告错误。

可能:

1, 你用vc建了一个控制台程序,它的入口函数应该是main, 而你使用了WinMain.

2. 你用vc打开了一个.c/.cpp 文件,而后直接编译这个文件,这个文件中使用了WinMian而不是main做为入口函数。vc这时的默认设置是针对控制台程序的。

3.根本就没有WinMain或Main函数。

三, 解决方法
1.进入project->setting->c/c++, 在category中选择preprocessor,在processor definitions中删除_CONSOLE, 添加_WINDOWS

2.进入project->setting->Link, 在Project options中将 /subsystem:console改成/subsystem:windows.

3.保存设置,Rebuild All.

四,VS2008中的设置

1.菜单中选择 Project->Properties, 弹出Property Pages窗口

2.在左边栏中依次选择:Configuration Properties->C/C++->Preprocessor,而后在右边栏的Preprocessor Definitions对应的项中删除_CONSOLE, 添加_WINDOWS.

3.在左边栏中依次选择:Configuration Properties->Linker->System,而后在右边栏的SubSystem对应的项改成Windows(/SUBSYSTEM:WINDOWS)

4.Rebuild All. Ok ?

================================================================

九、fatal error LNK1112: 模块计算机类型“ARM”与目标计算机类型“X86”冲突

fatal error LNK1112: 模块计算机类型“ARM”与目标计算机类型“X86”冲突

解决方法:连接器 -> 命令行 -> 附加选项, 添加 /MACHINE:ARM /MACHINE:THUMB

 

fatal error LNK1112: 模块计算机类型“THUMB”与目标计算机类型“ARM”冲突

解决方法:

第1种:连接器 -> 命令行 -> 附加选项, 添加 /MACHINE:THUMB

第2种:新建项目时,在"平台"->"选择要添加到当前项目中的 Platform SDK。"中,把"已安装的 SDK"所有添加到"选定的 SDK"

若是是直接使用已经建立好的工程,那么第一种方法就能够解决了,实在不行,就只有采用第二种办法从头解决了 。

 

================================================================

十、error c3872: “0x3000”: 此字符不容许在标识符中使用

例如friend ostream& operator<<(ostream& out,const Chain<T>& x );
出错error c3872: “0x3000”: 此字符不容许在标识符中使用

解决方法:

0x3000是汉语的空格,也就是全角空格,至关于一个汉字,但你又看不见它。

像逗号,有半角(,)和全角(,)之分的,其实空格也有。
0x3000是全角的空格,0x20是半角的空格。

你最好把这个语句的后面空白部分都删除掉,并检查是否有中文标点存在

================================================================

十一、0x????处未处理的异常:0xC0000005

    使用VC编码的时候常常会出现“Test.exe 中的 0x00414030 处未处理的异常: 0xC0000005: 写入位置 0xfeeefeee 时发生访问冲突 。

     出现0xC0000005的缘由通常都是没有分配内存 或者 内存无效 所致,

例如:

#include "stdafx.h"
#include <string>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

string * s = NULL;
s = new string();
delete s;

if (s != NULL)
{
   *s = "TEST"; //这步操做将引发异常。
}

return 0;
}

虽然s已经被delete了,可是s的值并不为NULL,if语句的判断将失效,这是新手常见的一个错误!

为了防止这个错误能够本身定义一个宏来处理delete。

#define _DELETE(obj) if (obj != NULL) {delete obj , obj = NULL;}

使用这个宏能够防止相似错误出现。

 

================================================================

十二、没有找到MFC80UD.DLL,所以这个程序未能启动.从新安装应用程序可能会修复此问题

在vs2005 sp1中文版中,在“解决方案资源管理器”中的项目上右击,选择“属性”,找到“配置属性”中的“连接器”,而后找到“清单文件”,在右边的属性框中,默认“生成清单”项为“是”,选 把“是”改为“否”,运行之,出错,而后再把否改回来,OK

其余:

1)若是不选"系统菜单""关于菜单"就不会有这个问题!
2)若是在"工程属性->配置属性->常规->字符集""使用多字节字符集"也不会出这个问题!
3)好像是删除全部的中间文件,(具体一点说,就是删除."(工程文件)"Debug里的文件和.ncb),"从新生成解决方案文件...",可能能够.
4clean关闭vs,打开rebuild应该就能够了,个人不多遇到。遇到以后这样就解决了。不行就多试几回。
5linker-manifest-file-Generate Manifest: Yes
6Manifest搞的鬼,而后修改项目属性,清单工具中的输入输出把嵌入清单文件选否.而后编译,连接运行,成功

debug---动态使用dll
release---静态使用dll

debug状态下使用,会时不时出这个问题;
release状态下使用,不会出现这个问题。

 

================================================================

1三、没有找到MFC80D.DLL或msvcr80d.dll的解决方法

   解决方案:

在编辑状态下,点项目菜单 -> XXX属性页 -> 配置属性 -> 清单工具,将右面的使用FAT32解决办法选为便可。简单地,其实把程序目录下的Debug目录整个删掉,再让VS所有从新生成文件也能解决这个问题,只是可能再犯。

没有找到MFC80D.DLL的解决方法。问题出如今程 序运行清单上,默认是"嵌入清单",清单文件是"$(IntDir$(TargetFileName).embed.manifest"。调试程序运行 时,不知道为何却定位不到这个文件,咱们若是手动把"程序名.embed.manifest"改成"程序名.manifest",调试程序便可定位到。

其余

方法一:
在C:Program FilesMicrosoft Visual Studio 8VCredi
stDebug_NonRedistx86Microsoft.VC80.DebugCRT 下找到了下列文件:

msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
Microsoft.VC80.DebugCRT.manifest

把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,就能够运行那个程序了。

方法二:
修改编译选项,将/MD或/MDd 改成 /MT或/MTd,这样就实现了对VC运行时库的静态连接,在运行时就再也不须要VC的dll了。

 

================================================================

1四、fatal error LNK1181: 没法打开输入文件“..filename.lib”

连接器未能找到 filename,由于该文件不存在或未找到路径。

如下常见缘由可致使错误 LNK1181:

filename 在连接器行上做为附加依赖项被引用,但该文件不存在。

缺乏用于指定包含 filename 的目录的 /LIBPATH 语句。

若要解决上面的问题,请确保连接器行上引用的任何文件在系统中存在。 另外,请确保对于包含依赖于连接器的文件的每一个目录都存在 /LIBPATH 语句。

致使 LNK1181 的另外一可能缘由是具备嵌入空格的长文件名没有括在引号内。 在这种状况下,连接器仅将文件名识别到第一个空格处,而后假定文件的扩展名为 .obj。 此状况的解决方案是将长文件名(路径和文件名)括在引号内。

 

================================================================

1五、没有找到MFC80D.DLL,所以这个程序未能启动.从新安装应用程序可能会修复此问题

解决方法:删除程序目录下Debug文件夹和Release文件夹,而后从新编译执行。

===网上其余方法=============

方法一:
没 有找到MFC80D.DLL的解决方法。问题出如今程序运行清单上,默认是"嵌入清单",清单文件是 "$(IntDir$(TargetFileName).embed.manifest"。调试程序运行时,不知道为何却定位不到这个文件,咱们若是 手动把"程序名.embed.manifest"改成"程序名.manifest",调试程序便可定位到。

方法二:
在C:Program FilesMicrosoft Visual Studio 8VCredistDebug_NonRedistx86Microsoft.VC80.DebugCRT 下找到了下列文件:
msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
Microsoft.VC80.DebugCRT.manifest
把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,就能够运行那个程序了。

方法三:
修改编译选项,将/MD或/MDd 改成 /MT或/MTd,这样就实现了对VC运行时库的静态连接,在运行时就再也不须要VC的dll了。

 

================================================================

1六、mspdb80.dll没法找到的解决方法

在cmd中键入cl执行编译时会出现mspdb80.dll没法找到的状况,是由于VCBin下没有“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件,解决的方法:
1>直接从Microsoft Visual Studio 8Common7IDE下复制这四个文件到Microsoft Visual Studio 8VCBin下便可解决
2> 添加系统变量(Path),这样:个人电脑->属性->高级->环境变量->系统变量,在path中添加C:Program FilesMicrosoft Visual Studio 8Common7IDE;,注意结尾最后用“;”隔开!
这样在用cl编译就不会出现mspdb80.dll文件找不到的错误了。

 

================================================================

1七、error LNK2019: 没法解析的外部符号....该符号在函数 ...中被引用

这种状况通常都是函数只找到声明但没有实现,或者是少了什么连接库,你能够试试把那两个.h和.c文件直接加入工程中再试试。

有一个解决方案,有两个工程A,B。工程B中定义了一个类,在工程A的demo.cpp中引用该类,可是若是是

#include "XX,h",则会出现“error LNK2019: 没法解析的外部符号”

若是是#include "XX.cpp",则能够顺利编译经过。

想来是由于引用 .h 文件致使找不到.cpp中的定义,而引用.cpp能够经过.cpp找到.h(.cpp有对.h的include)

可是若是同在工程B下面,则#include "XX,h"也是正确的,它会自动关联到同名的(反正是对应的).cpp文件。

在不一样工程中应该如何引用呢?

看见一种缘由分析,以下:

现场状况:

funcname 在文件file.cpp/h中定义实现

void funcname(void) {;}

filecall.c文件内呼叫funcname()函数。

出现上面状况。

症因:因c/c++混合编程, c文件内函数没法呼叫c++文件内函数。

解决,或者将c文件名改成.cpp,或者将c++文件名改成.c

上面的解决采用将 file.cpp 改名为file.c便可。

1.
在 Visual C++ .NET 2003 中,若是使用了 /clr 而未将 CRT 连接到可执行文件,将生成此错误。任何由编译器在未使用 /clr:initialAppDomain 时生成的对象代码都包含对 _check_commonlanguageruntime_version 函数的引用,该函数在 C 运行时库 (CRT) 中定义。若是应用程序在运行库的版本 1 上运行,该函数将会生成一个错误信息。当前编译器生成的代码与运行库的版本 1 不兼容。所以,若是在 Visual C++ .NET 2003 中编译时不使用 CRT,则应在代码中包含 _check_commonlanguageruntime_version 函数的定义。做为使用 _check_commonlanguageruntime_version 函数的替代方法,您能够与 nochkclr.obj 连接。nochkclr.obj 包含该函数的一个空版本,当您在运行库的版本 1 上运行应用程序时,nochkclr.obj 不生成错误信息。若要使用当前编译器版本生成应用程序以在运行库的之前版本上运行,应使用 /clr:InitialAppDomain。
若要 生成一个纯 MSIL 可执行文件(不与 CRT 连接),则必须在项目中定义该函数,而不能使用 nochkclr.obj(.obj 是本机代码)。有关可验证代码的更多信息,请参见产生可验证的 C++ 托管扩展组件。有关从托管 C++ 项目建立纯 MSIL 输出文件的更多信息,请参见将 C++ 托管扩展项目从混合模式转换成纯 IL。

2.
请看下面的示例:
extern int i;
extern void g();
void f()
{
i++;
g();
}
int main()
{
}
若是在生成中包含的某个文件中没有定义 i 和 g,连接器将生成 LNK2019。能够添加这些定义,方法是将包含这些定义的源代码文件包括为编译的一部分。或者能够将包含这些定义的 .obj 或 .lib 文件传递给连接器。


3.
对于从早期版本升级到当前版本的 C++ 项目,若是定义了 __UNICODE 而且入口点为 WinMain,须要将入口点函数的名称更改成 _tWinMain 或 _tmain。

4.
符号声明包含拼写错误,以至于符号声明与符号定义不一样。

5.
使用了一个函数,但其参数的类型或数量与函数定义不匹配。
函数声明使用和函数定义使用中的调用约定(__cdecl、__stdcall 或 __fastcall)不一样。

6.
符号定义在编译为 C 程序的文件中,而符号是在 C++ 文件中不带 extern "C" 修饰符声明的。在此状况下,请修改声明,例如不是使用:
extern int i;
extern void g();
而使用:

extern "C" int i;
extern "C" void g();
一样,若是在将由 C 程序使用的 C++ 文件中定义符号,请在定义中使用 extern "C"。


7.
符号定义为静态,但稍后在文件外部被引用。
没有定义静态类成员。例如,应单独定义下面类声明中的成员变量 si:
#include <stdio.h>
struct X {
static int si;
};

// int X::si = 0; // uncomment this line to resolve

void main()
{
    X *px = new X[2];
    printf("n%d",px[0].si); // LNK2019
}

8.
也可能因为为 Visual Studio .NET 2003 进行的一致性工做生成此错误:模板友元和专用化。在 Visual Studio .NET 2003 中,必须定义声明新的非模板函数的友元声明。
要使代码在 Visual C++ 的 Visual Studio .NET 2003 和 Visual Studio .NET 版本中均有效,请显式指定友元函数的模板参数列表。
// LNK2019.cpp
// LNK2019 expected
template<class T>
void f(T)
{
}

template<class T>
struct S
{
    friend void f(T);
    // Try the folowing line instead:
    // friend void f<T>(T);
};

int main()
{
    S<int> s;
    f(1); // unresolved external
}


/VERBOSE 连接器选项帮助您查看连接器引用的文件。DUMPBIN 实用工具的 /EXPORT 和 /SYMBOLS 选项还能够帮助您查看 dll 和对象/库文件中定义的符号。

-------------------------------------

例如“error LNK2019: 没法解析的外部符号_imp__SetupDiGetDeviceInterfaceDetailW@24
error LNK2001: 没法解析的外部符号“private: static struct _OVERLAPPED CUsbCom::g_WriteOverlapped”

应该是工程设置的问题 没有链接相应的lib库或者是所用到的函数没定义(这个定义是在别的类里面的)

当出现error LNK2001: 没法解析的外部符号 _print_interface   log.obj      可在log.c里搜print_interface(无前面_),找到此函数,看有无定义学习VC++时常常会遇到连接错误LNK2001,该错误很是讨 厌,由于对于 编程者来讲,最好改的错误莫过于编译错误,而通常说来发生链接错误时,编译都已经过。产生链接错误的缘由很是多,尤为LNK2001错误,经常令人不 明其因此然。若是不深刻地学习和理解VC++,要想改正链接错误LNK2001非 常困难。
初学者在学习VC++的过程当中,遇到的LNK2001错误的错误消息主要为:
unresolved external symbol “symbol”(不肯定的外部“符号”)。 若是链接程序不能在全部的库和目标文件内找到所引用的函数、变量或 标签,将产生此错误消息。通常来讲,发生错误的缘由有两个:一是所引用 的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不一样版本的链接库。
如下是可能产生LNK2001错误的缘由:
一.因为编码错误致使的LNK2001。
1.不相匹配的程序代码或模块定义(.DEF)文件能致使LNK2001。例如, 若是在C++ 源文件内声明了一变量“var1”,却试图在另外一文件内以变量 “VAR1”访问该变量,将发生该错误。
2.若是使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将致使LNK2001错误。
3.调用函数时若是所用的参数类型同函数声明时的类型不符将会产生 LNK2001。
4.试图从基类的构造函数或析构函数中调用虚拟函数时将会致使LNK2001。
5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。
静态函数和静态变量具备相同的使用范围限制。当试图从文件外部访问任何没有在该文件内声明的静态变量时将致使编译错误或LNK2001。函数内声明的变量(局部变量) 只能在该函数的范围内使用。
C++ 的全局常量只有静态链接性能。这不一样于C,若是试图在C++的 多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是须要时在头文件中加入该常量的初始化代码,并在.CPP文件中包含该头文件;另外一种 方法是使用时给该变量赋以常数。
二.因为编译和连接的设置而形成的LNK2001
1.若是编译时使用的是/NOD(/NODEFAULTLIB)选项,程序所须要的运行库和MFC库在链接时由编译器写入目标文件模块, 但除非在文件中明确包含 这些库名,不然这些库不会被连接进工程文件。在这种状况下使用/NOD将导 致错误LNK2001。
2.若是没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将获得“unresolved external on _WinMain@16”的LNK2001错误信息。
3.使用/MD选项编译时,既然全部的运行库都被保留在动态连接库以内,源文件中对“func”的引用,在目标文件里即对“__imp__func” 的引用。
若是试图使用静态库LIBC.LIB或LIBCMT.LIB进行链接,将在__imp__func上发 生LNK2001;若是不使用/MD选项编译,在使用MSVCxx.LIB链接时也会发生LNK2001。
4.使用/ML选项编译时,如用LIBCMT.LIB连接会在_errno上发生LNK2001。
5.当编译调试版的应用程序时,若是采用发行版模态库进行链接也会产生LNK2001;一样,使用调试版模态库链接发行版应用程序时也会产生相同的 问题。
6.不一样版本的库和编译器的混合使用也能产生问题,由于新版的库里可 能包含早先的版本没有的符号和说明。
7.在不一样的模块使用内联和非内联的编译选项可以致使LNK2001。若是建立C++库时打开了函数内联(/Ob1或/Ob2),可是在描述该函数的相应 头文件里却关闭了函数内联(没有inline关键字),这时将获得该错误信息。 为避免该问题的发生,应该在相应的头文件中用inline关键字标志内联函数。
8.不正确的/SUBSYSTEM或/ENTRY设置也能致使LNK2001。 其实,产生LNK2001的缘由还有不少,以上的缘由只是一部分而已,对初 学者来讲这些就够理解一阵子了。可是,分析错误缘由的目的是为了不错 误的发生。LNK2001错误虽然比较困难,可是只要注意到了上述问题,仍是可以避免和予以解决的。

既然编译经过了,就说明了没有语法错误,不用在代码中死抠语法了。从错误中提示中找缘由吧。

通常问题出在

(1)XXX.lib头文件,这个要包含(否则编译也不能经过)

(2)须要XXX.lib或XXX.dll库。手动添加,项目->属性->配置属性->连接器->输入 而后在附件依赖项添加XXX.lib,再生成第一个没法解析的外部符号错误消失了。

 

================================================================

1八、Visual Studio 2005不能进行调试,错误126: 找不到指定的模块

Visual Studio 2005一直不能进行调试,查看出错的缘由,是由于Terminal Services服务不能正确启动。在【服务】里尝试启动Termial Services服务时,一直提示【 错误126: 找不到指定的模块 】的错。上网搜索了一下,发现了这样的信息:
错误126:找不到指定的模块 1. 故障现象尝试在“服务”管理单元窗口手动启动服务时,系统提示“错误126:找不到指定的模块”(Error 126: The specified module could not be found.), 2.缘由分析该故障一般在由svchost服务宿主进程所启动的服务上发生。这一类的Windows服务,实际上是以dll模块的形式插入某个 svchost进程。若是该dll文件被破坏,或者注册表的相关键值被篡改,均可能致使问题。这类服务所对应的Dll文件,是由HKLMSYSTEM CurrentControlSetServicesServiceNameParameters注册表项下的ServiceDll键值所定义的 (此处的ServiceName是指服务名),若是该注册表键值出错,或者对应的Dll文件被破坏,就会致使这个问题。

经过查看注册表文件,发现【Terminal Services】服务对应与 %SystemRoot%System32termsrv.dll 文件。查看个人本地文件,不知道什么时候这个文件名称被修改了termsrv.dl_。

修改成termsrv.dll后,再启动【Terminal Services】服务,正常启动,调试Visual Studio 2005项目,一切OK!

 

================================================================

1九、MFC 对话框不能显示中文

在资源视图中右击对话框ID,选属性,修改语言设置

================================================================

20、error C2248: 'CObject::operator =' : cannot access private member declared in class

1>e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafxtempl.h(776) : error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
1>        e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafx.h(562) : see declaration of 'CObject::operator ='
1>        e:program filesmicrosoft visual studio 9.0vcatlmfcincludeafx.h(532) : see declaration of 'CObject'
1>        This diagnostic occurred in the compiler generated function 'CList<TYPE,ARG_TYPE> &CList<TYPE,ARG_TYPE>::operator =(const CList<TYPE,ARG_TYPE> &)'
1>        with
1>        [
1>            TYPE=CProgram,
1>            ARG_TYPE=CProgram &
1>        ]

上面这段编译器报警是否是有似曾相识的感受?想必不少人在用VC2005以及以后的版本的VC编译器时看到过这个东西,在google查一下error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'你会发现不少人碰到相似的问题。一位叫“中国民工”的blog中说明了引起这一问题的的缘由,请参见http://www.cppblog.com/hlong/archive/2007/11/20/37015.html

根据民工兄的解释,因为咱们的类中定义了CArray类型的成员,而CArray<A, A&>类的operator=是private类型(它继承自CObject::operator=,且被定义为private类型)。并给出了解决之道:若是咱们的类/结构体中有CArray(或CList等其余的派生自CObject类)的成员变量,咱们最好添加上一个public类型的operator=运算赋重载函数;

问题虽然是解决了,可是彷佛仍是没弄明白产生问题的根本缘由:既然问题是因为CArray没有定义Operator=操做从而致使须要调用基类CObject中的私有Operator= 操做而引发的,那么为何微软要将CObject的Operator=操做定义成私有呢?或者说为何CObject在实际上并无对Operator= 和拷贝构造函数作任何实质性的定义的状况下要去定义这两个函数,而且还将他们定义为private。。惟一的解释就是微软不但愿继承自CObject的类 使用默认的Operator=操做,或者说微软不但愿使用了CArray或者CList或者CMap的Collections模板类的类使用默认的Operator=操做。答案的确是如此,不只如此,对于默认的拷贝构造函数结论也是同样(可能有些人碰到到一样的编译器报错,不过是针对拷贝构造函数的,后面我会解释引起这两种类型的报错的真正缘由)。

要想搞清楚这个问 题,就先要了解C++编译器生成的默认函数——这些咱们平时一直在使用却不多关心的幕后工做者究竟是怎样工做的。当咱们建立一个C++变量,为一个变量赋 值,或者调用一个C++函数,或者对一个C++变量进行取地址&操做时,这些都是一些基本操做,咱们老是能获得咱们想要的结果(至少看起来是这 样)由于这些都是C++的语义,而负责实现这些语义的是C++编译器。

编译器又是如何实 现这些语义的呢,好比当你构造一个C++变量时,编译器会检查你有没有为这个变量的类型建立一个构造函数,若是没有,编译器会本身帮你生成一个默认的构造 函数,从而实现了一个C++变量的构造;相似的,在用户执行其余一些诸如赋值操做,拷贝构造,取地址等基本操做时,编译器遵循一样的原则,即在用户未定义 相应的操做状况下自动生成一个默认的操做;正由于如此,甚至不少程序员并不知道它们的存在(我记得几年前我去一家公司面试的时候,就被问及过这样一个问题:C++类的默认函数有几个,分别是什么,,其实这是一个蛮深入的问题),即便知道它们,也会以为在不须要咱们付出任何关心的状况下,这些操做都是理所应当应该是正确的,可是事实并不是老是如此。

Effective C++在条款45也对这几个函数进行了比较详细的分析;其中构造函数和析构函数其实就是一个空函数,什么也不作,因此当咱们用VC也好或者其余的C++编 译器建立一个空类也好,编译器都会为咱们的类事先定义一个构造和析构函数,就是为了避免让咱们去使用默认的构造和析构函数。因此通常状况下咱们不多会忽视这 两个函数的存在,可是另外3个很重要的函数:拷贝构造和赋值操做符,以及取地址操做符就很容易被忽视掉,由于咱们不多去实现这3个操做,大部分都是使用的 编译器提供的默认的实现。

对于默认赋值操做符和拷贝构造函数的默认实现,Effective C++上的解释是:官 方的规则是:缺省拷贝构造函数(赋值运算符)对类的非静态数据成员进行 "以成员为单位的" 逐一拷贝构造(赋值)。即,若是m是类C中类型为T的非静态数据成员,而且C没有声明拷贝构造函数(赋值运算符),m将会经过类型T的拷贝构造函数(赋值 运算符)被拷贝构造(赋值)---- 若是T有拷贝构造函数(赋值运算符)的话。若是没有,规则递归应用到m的数据成员,直至找到一个拷贝构造函数(赋值运算符)或固定类型(例 如,int,double,指针,等)为止。默认状况下,固定类型的对象拷贝构造(赋值)时是从源对象到目标对象的 "逐位" 拷贝。对于从别的类继承而来的类来讲,这条规则适用于继承层次结构中的每一层,因此,用户自定义的构造函数和赋值运算符不管在哪一层被声明,都会被调用。

另一个很重要的概念是:当且仅当相应的操做被定义时,编译器才为操做变量所属的类型生成对应的默认操做;也就是说,若是代码中没有出现相应的操做,编译器什么也不会作。

再回到咱们一开始民工兄的例子中,假设咱们的类C中定义了一个CArray类型的成员变量,而且C中没有显示的定义operator=操做(这就意味着编译器可能须要为C自动生成一个默认的operator=操做)根据上面的说法,当且仅当C的实例被赋值时编译器才会生 成默认的operator=操做,而编译器报警告诉咱们,编译器在生成operator=操做时遇到了障碍,这个障碍就是:C的CArray成员具备一个 赋值运算符定义,可是该定义是私有的(其实是CArray继承自CObject的operator=定义)。。咱们看一下民工兄的例子的源码:

3struct A
4
{
5
     int a;
6
};
7

8struct B
9
{
10      CArray<A, A&> b;

24};
25

26 typedef CArray<B, B&> C;
27

28void test()
29
{
30
     B b;
31
     C c;
32
     c.Add(b);
33 }

从这段代码中能够看出,test中对B的实例b并无作任何赋值的操做,为何编译器会去实现B的默认operator=操做呢?

问题就处在CArray::Add()的函数签名身上,Add函数的源码以下

template<class TYPE, class ARG_TYPE>
AFX_INLINE INT_PTR CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
{ INT_PTR nIndex = m_nSize;
   SetAtGrow(nIndex, newElement);

   return nIndex; }

可见,形参newElement的类型是ARG_TYPE,ARG_TYPE其实就是TYPE的引用,在这里就是B的引用;答案彷佛明了了:

由于Add函数的签名要求输入参数的类型为B&,因此当编译器编译语句:c.Add(b); 时会自动将b强制转换成B的引用,即将这条语句编译成:B& d = b; c.Add(d); 赋值操做就这样出现了!

为了验证这个想法,能够作另外一个测试,调用一个传值的函数,这样就不须要作“B& d = b;”的转换了,那么就应该不会有问题了。

很不幸,实际上编译器会报一样的错误,只是如今不是operator=而是拷贝构造函数。

原 因很简单,由于对于传值的方式,实际上就是“经过值来传递一个对象”,而这又是由这个对象的类的拷贝构造函数定义的。也就是说当经过传值的方式调用一个子 程序时,最终是编译器经过调用拷贝构造函数来实现的。因此问题是同样的,由于类型B没有定义本身的拷贝构造函数,因而编译器试图生成一个默认的,但它一样 遇到了障碍,由于CArray的拷贝构造也是private的(一样继承于CObject)。

至此,咱们对于这个问题有了一个比较全面的认识,其实问题的本质在于:不管是默认的operator=仍是默认的拷贝构造也好都是有其致命的缺陷的,正如Effective C++条款11中所描述的,当这些默认的实如今遇到须要动态分配内存的类的时候就会出现问题,也就是所谓的深拷贝问题。而Collections模板类就是典型的不能使用默认operator=和默认的拷贝构造的例子。

因此当咱们自定义的类中包含Collections模板类的成员时咱们就无法再偷懒使用编译器自动生成的operator=和的拷贝构造了,而必须本身动手实现,这也是微软想提醒咱们的一个事实。


================================================================
2一、
error : WINDOWS.H already included. MFC apps must not #include <windows.h>

在windows console下编译 的时候遇到这个问题的

#include <afx.h>//由于要用到CString因此要包含这个头文件
#include <iostream>

using namespace std;

后来把头文件包含位置换了下 编译经过
#include <afx.h>//由于要用到CString因此要包含这个头文件

#include <iostream>
using namespace std;

error是由于将#include<stdafx.h>放在其它#include的后面了。
这个文件应该放在最前面。