編譯時提示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。
======================================================================
4、 error:無法執行添加/移除操作,因為代碼元素是只讀的
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
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()
{
cout<<"123";
return 0;
}
LINK : 沒有找到 D:Visual Studio 2008ProjectstestDebugtest.exe 或上一個增量鏈接沒有生成它;正在執行完全鏈接
出現這個提示,
1.你是第一次進行編譯,這時當然沒有生成過可執行文件,也就無法增量鏈接了。
2.你上一次編譯的時候有錯誤,沒有生成可執行文件。
================================================================
7、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
================================================================
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<<(ostream& out,const Chain<T>& x );
出錯error c3872: “0x3000”: 此字符不允許在標識符中使用
解決方法:
0x3000是漢語的空格,也就是全角空格,相當於一個漢字,但你又看不見它。
像逗號,有半角(,)和全角(,)之分的,其實空格也有。
0x3000是全角的空格,0x20是半角的空格。
你最好把這個語句的后面空白部分都刪除掉,並檢查是否有中文標點存在。
================================================================
11、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;}
使用這個宏可以防止類似錯誤出現。
================================================================
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”
以下常見原因可導致錯誤 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 <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,再生成第一個無法解析的外部符號錯誤消失了。
================================================================
18、Visual Studio 2005不能進行調試,錯誤126: 找不到指定的模塊
通過查看注冊表文件,發現【Terminal Services】服務對應與 %SystemRoot%System32termsrv.dll 文件。查看我的本地文件,不知道何時這個文件名稱被修改了termsrv.dl_。
修改為termsrv.dll后,再啟動【Terminal Services】服務,正常啟動,調試Visual Studio 2005項目,一切OK!
================================================================
在資源視圖中右擊對話框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<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=和的拷貝構造了,而必須自己動手實現,這也是微軟想提醒我們的一個事實。
================================================================
21、 error : WINDOWS.H already included. MFC apps must not #include <windows.h>
在windows console下編譯 的時候遇到這個問題的
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
這個文件應該放在最前面。
編譯時提示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。
======================================================================
4、 error:無法執行添加/移除操作,因為代碼元素是只讀的
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
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()
{
cout<<"123";
return 0;
}
LINK : 沒有找到 D:Visual Studio 2008ProjectstestDebugtest.exe 或上一個增量鏈接沒有生成它;正在執行完全鏈接
出現這個提示,
1.你是第一次進行編譯,這時當然沒有生成過可執行文件,也就無法增量鏈接了。
2.你上一次編譯的時候有錯誤,沒有生成可執行文件。
================================================================
7、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
================================================================
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<<(ostream& out,const Chain<T>& x );
出錯error c3872: “0x3000”: 此字符不允許在標識符中使用
解決方法:
0x3000是漢語的空格,也就是全角空格,相當於一個漢字,但你又看不見它。
像逗號,有半角(,)和全角(,)之分的,其實空格也有。
0x3000是全角的空格,0x20是半角的空格。
你最好把這個語句的后面空白部分都刪除掉,並檢查是否有中文標點存在。
================================================================
11、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;}
使用這個宏可以防止類似錯誤出現。
================================================================
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”
以下常見原因可導致錯誤 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 <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,再生成第一個無法解析的外部符號錯誤消失了。
================================================================
18、Visual Studio 2005不能進行調試,錯誤126: 找不到指定的模塊
通過查看注冊表文件,發現【Terminal Services】服務對應與 %SystemRoot%System32termsrv.dll 文件。查看我的本地文件,不知道何時這個文件名稱被修改了termsrv.dl_。
修改為termsrv.dll后,再啟動【Terminal Services】服務,正常啟動,調試Visual Studio 2005項目,一切OK!
================================================================
在資源視圖中右擊對話框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<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=和的拷貝構造了,而必須自己動手實現,這也是微軟想提醒我們的一個事實。
================================================================
21、 error : WINDOWS.H already included. MFC apps must not #include <windows.h>
在windows console下編譯 的時候遇到這個問題的
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
這個文件應該放在最前面。