`
gzg844cz
  • 浏览: 41681 次
社区版块
存档分类
最新评论

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

 
阅读更多

[转载]C/C++/MFC 编译运行错误解决方法收集error
2011年12月19日
  编译时提示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
  ================================================== ============
  2、error C2471: 无法更新程序数据库 ,fatal error C1083: 无法打开程序数据库文件 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一下就行了
  ================================================== ============== 3、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++->预编译头 的右侧第一项。
  ================================================== ====================
  4、
  vc2005error:无法执行添加/移除操作,因为代码元素是只读的
  出现这种现象,多数是因为你的工程所在文件夹的属性设置为了“只读”,你可以关闭解决方案,然后重新打开,就可以了,如果以后不想出现这样的情况,把工程所在的文件夹属性中的“只读”去掉,就可以了。
  解决方案:
  1、重启VS2005
  2、查看.h和.cpp文件的属性,有可能是只读的,修改属性后就可以了
  3、打开Resource.h文件看看 一看就知道了 有些定义重复了 可以手动改掉 保存 编辑器重新加载
  4、把你要添加事件的对话框相应的类文件(*.h和*.cpp)给关了就可以了
  5、关闭解决方案,删除.ncb文件重新添加即可
  6、实在不行就手动添加消息处理
  在BEGIN_MESSAGE_MAP(。。。)
  //这里要删掉你原先已经增加过的消息隐射函数
  END_MESSAGE_MAP()
  ================================================== ============== 5、程序运行出现-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
  ================================================== ============== 6、LINK : 上一个增量链接没有生成它;正在执行完全链接 代码 #include"iostream"
  using namespace std;
  int main()
  {
  couterror 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(pNMHDR);
  ; 改为: LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR);
  参考: http://connect.microsoft.com/VisualStudio/feedback /ViewFeedback.aspx?FeedbackID=339678
  ================================================== ==============
  8、无法解析的外部符号 _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 ? ================================================== ============== 9、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
  "
  如果是直接使用已经创建好的工程,那么第一种方法就可以解决了,实在不行,就只有采用第二种办法从头解决了。 ================================================== ============== 10、error c3872: “0x3000”: 此字符不允许在标识符中使用 例如friend ostream& operator& x );
  出错error c3872: “0x3000”: 此字符不允许在标识符中使用
  解决方法:
  0x3000是汉语的空格,也就是全角空格,相当于一个汉字,但你又看不见它。
  像逗号,有半角(,)和全角(,)之分的,其实空格也有。
  0x3000是全角的空格,0x20是半角的空格。
  你最好把这个语句的后面空白部分都删除掉,并检查是否有中文标点存在。
  ================================================== ============== 11、0x????处未处理的异常:0xC0000005     使用VC编码的时候经常会出现“Test.exe 中的 0x00414030 处未处理的异常: 0xC0000005: 写入位置 0xfeeefeee 时发生访问冲突。”
  出现0xC0000005的原因一般都是没有分配内存 或者 内存无效 所致,
  例如:
  #include "stdafx.h"
  #include 
  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;}
  使用这个宏可以防止类似错误出现。 ================================================== ============== 12、没有找到MFC80UD.DLL,因此这个程序未能启动.重新安装应用程序可能会修复此问题
  在vs2005 sp1中文版中,在“解决方案资源管理器”中的项目上右击,选择“属性”,找到“配置属性”中的“链接器”,然后找到“清单文件”,在右边的属性框中,默认“生成清单”项为“是”,选把“是”改成“否”,运行之,出错,然后再把否改回来,OK。
  其他:
  (1)如果不选"系统菜单"和"关于菜单"就不会有这个问题!
  (2)如果在"工程属性->配置属性->常规->字符集"选"使用多字节字符集"也不会出这个问题!
  (3)好像是删除所有的中间文件,(具体一点说,就是删除."(工程文件)"Debug里的文件和.ncb),再"重新生成解决方案文件...",可能可以.
  (4)clean关闭vs,打开rebuild应该就可以了,我的很少遇到。遇到之后这样就解决了。不行就多试几次。
  (5)linker-》manifest-file-》Generate Manifest: Yes
  (6)Manifest搞的鬼,然后修改项目属性,清单工具中的输入输出把嵌入清单文件选否.然后编译,链接运行,成功
  debug---动态使用dll
  release---静态使用dll
  debug状态下使用,会时不时出这个问题;
  release状态下使用,不会出现这个问题。
  ================================================== ==============
  13、没有找到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了。 ================================================== ============== 14、fatal error LNK1181: 无法打开输入文件“..filename.lib” 链接器未能找到 filename,因为该文件不存在或未找到路径。
  以下常见原因可导致错误 LNK1181:
  filename 在链接器行上作为附加依赖项被引用,但该文件不存在。
  缺少用于指定包含 filename 的目录的 /LIBPATH 语句。
  若要解决上面的问题,请确保链接器行上引用的任何文件在系统中存在。 另外,请确保对于包含依赖于链接器的文件的每个目录都存在 /LIBPATH 语句。
  导致 LNK1181 的另一可能原因是具有嵌入空格的长文件名没有括在引号内。 在这种情况下,链接器仅将文件名识别到第一个空格处,然后假定文件的扩展名为 .obj。 此情况的解决方案是将长文件名(路径和文件名)括在引号内。
  ================================================== ============== 15、没有找到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了。
  ================================================== ==============
  16、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文件找不到的错误了。 ================================================== ============== 17、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 
  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
  void f(T)
  {
  }
  template
  struct S
  {
  friend void f(T);
  // Try the folowing line instead:
  // friend void f(T);
  };
  int main()
  {
  S 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,再生成第一个无法解析的外部符号错误消失了。 ================================================== ============== 18、Visual Studio 2005不能进行调试,错误126: 找不到指定的模块 Visual Studio 2005一直不能进行调试,查看出错的原因,是因为Terminal Services服务不能正确启动。在【服务】里尝试启动Termial Services服务时,一直提示【】的错。上网搜索了一下,发现了这样的信息:
  错误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!
  ================================================== ============== 19、 MFC 对话框不能显示中文
  在资源视图中右击对话框ID,选属性,修改语言设置
  ================================================== ============== 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 &CList::operator =(const CList &)'
  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/37 015.html
  根据民工兄的解释,由于我们的类中定义了CArray类型的成员,而CArray类的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     CArrayb;
  24};
  25
  26typedef CArrayC;
  27
  28void test()
  29{
  30     B b;
  31     C c;
  32     c.Add(b);
  33}
  从这段代码中可以看出,test中对B的实例b并没有做任何赋值的操作,为什么编译器会去实现B的默认operator=操作呢?
  问题就处在CArray::Add()的函数签名身上,Add函数的源码如下
  template
  AFX_INLINE INT_PTR CArray::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=和的拷贝构造了,而必须自己动手实现,这也是微软想提醒我们的一个事实。 在windows console下编译 的时候遇到这个问题的 error是因为将#include放在其它#include的后面了。
  这个文件应该放在最前面。
分享到:
评论

相关推荐

    清除c/c++代码中条件编译部分的程序,帮助阅读源代码,生成好的tags

    网上众多的开源C/C++代码,因为跨平台的需要,参杂了许多的条件编译语句,对阅读源代码造成了不方便,而且用ctags等工具生成源代码的tags文件时会有些妨碍,本工具就是用来预处理这些条件编译的,将未定义的区域自动...

    反编译工具(DLL 转c/c++ 工具)

    反编译工具(DLL 转c/c++ 工具); 内有工具使用说明。

    C语言/C++集成开发环境 Dev-C++

    C语言/C++集成开发环境 Dev-C++。一款优秀的C/C++集成开发软件。

    Pro*C/C++ 编程

    Pro*C/C++ 编程 1 一、Pro*C/C++ 简介 1 1.1、Pro*C/C++ 是什么 1 1.2、Pro*C/C++ 处理流程 2 二、Pro*C/C++ GCC 环境配置 3 2.1、Pro*C/C++ 预编译环境 3 2.2、GCC 编译器 5 三、开始编写第一个Pro*C++代码 5 3.1、...

    编译原理课程设计 词法分析 C语言/c++版

    编译原理课程设计之一用编程语言实现词法分析,用C++实现 注释清楚详细,程序风格良好 /*目前实现的功能有: */ /* 0.课程要求的词法分析基本功能 */ /* 1.识别用户定义的初次定义的变量还是已经定义的变量还是错误...

    C/C++程序设计学习与实验系统 V2008.13.part1

    课程设计指导、课程设计源程序、 Visual C++6.0中英文编译错误信息同步显示功能(并配有同步的60多个语法错误程序实例)、Turbo C++3.0常见编译错误信息、 Turbo C2.0 中英文编译错误信息同步显示功能、C语言专业词汇...

    MinGW64与32——C/C++快速配置编译环境

    为了考虑到程序兼容性,通常我们编译C/C++程序会编译32位和64位两个版本,像VisualStudio,devcpp这类集成开发环境确实不用自己设置就能做到,但是他们都有不方便的地方,如VisualStudio的占用空间太大,如果初学C/...

    C/C++/HTML/MFC实用库函数

    关于C/C++/HTML/MFC的chm文档,介绍了一些实用的库函数,编程时查询方便、快捷~~~~~~

    c/c++函数帮助/mfc类库手册

    c/c++函数帮助/mfc类库手册 mfc类库详解 · 层次结构图 直观的描述MFC中各类的关系。 · MFC类 详细解说MFC库中的每个类和头文件信息。 · MFC宏和全局 详细解说MFC库中的每个宏、全局函数、全局变量。 · ...

    c/c++中文帮助文档(API)

    c/c++中文帮助文档(API),包含c和c++所有的库函数

    俄罗斯方块MFC C/C++编写

    俄罗斯方块,MFC,C/C++编写,是学习MFC的好帮手。编译环境是VC++6.0,可以运行,重新开始。自己改写的别人的,亲测有效,增加了重新开始功能。

    GomokuGame(“四子棋”或“五子棋”两种模式).rar

    最终的exe游戏可以选择五子棋或四子棋两种模式,五子棋/四子棋/C语言/C++/MFC。 最终的exe游戏可以选择五子棋或四子棋两种模式,五子棋/四子棋/C语言/C++/MFC。 最终的exe游戏可以选择五子棋或四子棋两种模式,...

    C/C++编译技术

    本上传pdf文件主要讲解C/C++编译技术,适合入门者阅读。

    Tcl/Tk命令与C/C++的集成研究

    针对Tcl/Tk脚本中需要调用C/C++函数的问题,简要说明了Tcl/Tk命令的运行机理,给出了一个使用Tcl/Tk命令来调用C/C++动态链接库(DLL)函数的方案,并给出了将C/C++DLL函数封装为Tcl/Tk C库函数的解决方法.

    c/c++-mfc编程实例教程

    c/c++-mfc编程实例教程

    万能通用性Makefile/C++/C全自动编译实例

    Makefile编写实例: 1.前提是需要安装MInGw——c/c++编译器,不懂的可以私信我哈; 2.本程序是利用bat脚本直接运行Makefile,非常方便;直接点击运行“run.bat”即可编译,方便快捷。...4.适应于编译C++/C代码。

    c/c++石头剪子布小游戏,已经编译过的,可以直接运行的

    c/c++石头剪子布小游戏,已经编译过的,可以直接运行的 保你满意c/c++石头剪子布小游戏,已经编译过的,可以直接运行的 保你满意c/c++石头剪子布小游戏,已经编译过的,可以直接运行的 保你满意c/c++石头剪子布小...

    MinGW-w64 C/C++ 编译器

    压缩包内附:软件安装包,安装教程和环境变量配置教程 解决问题: ...你可以安装免费提供的MinGW-w64C/C++编译器;有关更多选项,请访问 http://www.mathworks.com/support/compilers/R20116b/win64.html。

    cJSON 可以直接在linux,或 windows C/C++编译器下直接编译使用

    cJSON 可以直接在linux,或 windows C/C++编译器下直接编译使用

Global site tag (gtag.js) - Google Analytics