共用方式為


Visual C++ 2005 編譯器的重大變更

更新:2007 年 11 月

本主題將討論 Visual C++ 2005 中的行為變更,這些變更使得原本在舊版中運作的程式碼變成不能編譯,或是在執行階段有不同的行為。

如需新功能的詳細資訊,請參閱 Visual C++ 2005 和舊版的變更Visual C++ 2005 程式庫的變更Visual C++ 2005 編譯器、語言和工具的變更

  • 成員指標現在需要使用限定名稱 (Qualified Name) 與 &
    針對只使用方法名稱的舊版編譯器所寫的程式碼,現在則會產生編譯器錯誤 C3867編譯器警告 C4867。根據 Standard C++,這是必要的診斷。現在若要建立成員指標函式,您必須使用傳址運算子 (&) 以及方法的完整限定名稱。如果不使用 & 運算子和方法的完整限定名稱,便可能因為程式碼的函式呼叫中缺少括弧而導致邏輯錯誤。若使用沒有引數清單的函式名稱,結果就會是可轉換成數種型別的函式指標。 如果編譯這個程式碼,就會在執行階段導致未預期的行為。

  • friend 宣告必須能夠存取類別
    Visual C++ 2005 之前的舊版 Visual C++ 編譯器允許對類別進行 friend 宣告,而該類別 (包含該宣告) 在其範圍中為無法存取。現在,編譯器會出現編譯器錯誤 C2248。若要解決這個錯誤,請變更 friend 宣告中所指定之類別的存取範圍。這項變更是為了符合 C++ 標準。

  • __int asm 3 現在會編譯為機器碼
    搭配 /clr 進行編譯時,__asm int 3 不會導致產生機器碼,編譯器會將該指令轉譯為 CLR 中斷指令。在 Visual C++ 2005 中,__asm int 3 現在會產生函式的機器碼。如果您希望某個函式在程式碼中產生中斷點,而且希望該函式編譯為 MSIL,請使用 __debugbreak。如需詳細資訊,請參閱 __asm/clr (Common Language Runtime 編譯)。這項變更的目的,是要讓產生機器碼的時機更具決定性 (相較於 Managed 程式碼而言);內嵌組譯程式碼 (Inline Assembly Code) 應該會產生機器碼。

  • 明確特製化不能做為複製建構函式/複製指派運算子
    依賴明確樣板特製化做為複製建構函式或複製指派運算子的程式碼,現在則會導致編譯器錯誤 C2299。Standard C++ 禁止這個動作。這項變更的目的是要符合一致性,提高程式碼的可移植性。

  • 非特製化類別樣板不能用來做為基底類別清單中的樣板引數
    針對類別定義在基底類別清單中使用非特製化樣板類別名稱,現在會導致編譯器錯誤 C3203。您不能使用非特製化樣板類別名稱做為基底類別清單中的樣板參數。使用它做為基底類別清單中的樣板參數時,您必須明確地將樣板型別參數加入至樣板類別名稱。這項變更的目的是要符合一致性,提高程式碼的可移植性。

  • 不再允許使用巢狀型別的 using 宣告
    包含巢狀型別之 using 宣告的程式碼現在會產生編譯器錯誤 C2885。若要解決巢狀型別的完整限定參考,請將型別放在命名空間中,或是建立 typedef。這項變更的目的是要符合一致性,提高程式碼的可移植性。

  • /clr:oldSyntax 下,編譯器不允許 const_cast 執行向下轉換
    Visual C++ 2005 之前的舊版 Visual C++ 編譯器在編譯使用 Managed Extensions for C++ 語法的原始程式碼時,允許 const_cast Operator執行向下轉換 (Down Cast)。使用 const_cast 執行向下轉換現在會導致編譯器錯誤 C2440。若要解決這個問題,請使用正確的轉型運算子 (如需需詳細資訊,請參閱Casting Operators)。這項變更的目的是要符合一致性。

  • 編譯器不允許 Managed 列舉的向前宣告
    Visual C++ 2005 之前的舊版 Visual C++ 編譯器允許 Managed 列舉的向前宣告。現在,當搭配任何形式的 /clr 進行編譯時,僅宣告而不定義 Managed 列舉將會導致編譯器錯誤 C2599。若要解決這個問題,請務必在宣告時定義 Managed 列舉。做出這項變更的原因,是因為編譯器無法正確識別列舉的基礎型別,所以 Managed 列舉不一定每一次都能正確運作。此外,C++ Standard 也不允許列舉宣告。

  • /YX 編譯器選項已經移除
    /YX 會產生自動先行編譯標頭支援。根據預設,它是用於開發環境中。如果您從組建組態中移除 /YX,而且沒有使用任何東西來取代,結果可能會造成建置加速除了使用 /YX 可能會發生未預期的行為之外,建議使用 /Yc (建立先行編譯標頭檔)/Yu (使用先行編譯標頭檔),因為它們都能讓您在先行編譯標頭方面擁有更多的控制能力。

  • /Oa/Ow 編譯器選項都已經移除
    /Ow/Oa 編譯器選項都已經移除並且會遭到忽略 (忽略時不會出現訊息)。請使用 noaliasrestrict__declspec 修飾詞來指定編譯器處理別名的方式

  • /Op 編譯器選項已經移除
    /Op 編譯器選項已經移除,請改用 /fp (指定浮點數行為)

  • /ML/MLd 編譯器選項都已經移除
    Visual C++ 不再提供單一執行緒、靜態連結的 CRT 程式庫支援。請改用 /MT/MTd。如需詳細資訊,請參閱 C Run-Time Libraries

  • /G3/G4/G5/G6/G7/GB 編譯器選項都已經移除
    編譯器現在是使用混合模型,它會針對所有架構試圖建立最佳輸出檔案。

  • /Gf 已經移除
    請改用 /GF (消除重複字串)/GF 會將已緩衝字串放在唯讀區段中,這比 /Gf 用來放置已緩衝字串的可寫入區段還要安全。

  • /clr/MT 不相容
    「C 執行階段程式庫」中不支援 Managed 應用程式的靜態連結。所有 Managed 應用程式都必須是動態連結 (/MD)。如需使用 /clr 時相關限制的詳細資訊,請參閱 /clr 限制

  • /GS 現在預設為開啟
    緩衝區溢位檢查在新版預設為開啟狀態,您可以使用 /GS- 關閉緩衝區滿溢檢查功能。如需詳細資訊,請參閱 /GS (緩衝區安全性檢查)

  • /Zc:wchar_t 現在預設為開啟
    以下是 Standard C++ 的行為:wchar_t 變數會預設為內建的型別,而非不帶正負號的短整數。如果不搭配 /Zc:wchar_t 而編譯的程式庫連結用戶端程式碼,這項變更會破壞二進位碼相容性 (LNK2019)。在此情況下,請使用 /Zc:wchar_t- 還原成舊版非標準的行為。預設會使用這項變更,以建立符合標準的程式碼。

    如需詳細資訊,請參閱/Zc:wchar_t (wchar_t 是原生型別)

  • /Zc:forScope 現在預設為開啟
    以下是 Standard C++ 的行為:在 for 迴圈範圍結束後,若程式碼依賴使用 for 迴圈中所宣告的變數,則現在將無法編譯此程式碼。請使用 /Zc:forScope- 還原成舊版非標準的行為。預設會使用這項變更,以建立符合標準的程式碼。

    如需詳細資訊,請參閱/Zc:forScope (強制 for 迴圈範圍中的一致性)

  • 強制執行 Visual C++ 屬性的參數檢查
    當型別不是字串時,若程式碼使用引號將具名屬性傳遞至屬性建構函式 (當型別是字串時,則不使用引號),現在則會導致編譯器錯誤 C2065編譯器警告 (層級 1) C4581。之前所有的編譯器屬性都會剖析成字串,如果有需要,編譯器也會插入遺漏的引號。藉由加入參數檢查驗證而增強了屬性支援,這可防止將不正確的引數傳遞至屬性建構函式所產生之無法預期的行為。

    針對這個發行版本,您無法在屬性 (會採用隱含字串當做引數) 的任何引數中使用多位元組字元字串 (MBCS),即使此字串已經用引號括住也一樣,這麼做會造成 .idl 檔案損毀。替代解決辦法如下:

    #define ARG string_with_MBCS_chars
    [helpstring(ARG)]
    
  • 針對相同型別的數個宣告,現在編譯器需要相同的樣板規格。
    例如,您使用了某個型別的向前宣告以建立數個該型別的 friend 宣告,則該型別的樣板規格必須對該型別的所有宣告而言都相同。否則,編譯器將出現編譯器錯誤 C2990

  • uuid 屬性不再以 Managed 型別做為目標
    之前可以對採用 Managed Extensions for C++ 的使用者定義屬性使用 uuid (C++ Attributes) 屬性,但是現在則會導致編譯器錯誤 C3451。請改用 GuidAttribute

  • 變更語法,以便將 Managed 陣列傳遞至自訂屬性
    陣列的型別不再是由彙總初始化清單推算而來。現在編譯器要求您指定陣列的型別以及初始設定式清單。使用舊語法將會導致編譯器錯誤 C3104。由於編譯器不一定每次都能從彙總初始化清單正確推算陣列型別,因此這項變更是必要的。

  • 編譯器不會在宣告中插入 int 做為預設型別
    對於宣告中遺漏型別的程式碼,現在不會再將型別預設為 int,而且編譯器將出現編譯器警告 C4430編譯器警告 (層級 4) C4431。Standard C++ 不支援預設的 int,而且這項變更可確保取得您真正想要的型別。

  • dynamic_cast 已經更加符合 C++ 標準。
    C 執行階段程式庫現在會進行 dynamic_cast 執行階段檢查,以確保編譯時期所轉換的運算式型別會參考到轉換目標型別 (針對向下轉換而言) 或最末層衍生的物件型別 (針對交叉轉換而言) 的公用基底類別 (Base Class) 子物件。如需詳細資訊,請參閱dynamic_cast 的重大變更

  • 值無法繫結至非常數參考。
    值無法繫結至非常數參考。在舊版 Visual C++ 中,可以在直接初始化中,將變數繫結至非常數參考。這個程式碼會產生編譯器警告 (層級 1) C4350

  • 實值型別 (Value Type) 將不再發出預設建構函式,這麼做會導致型別初始設定式在不同的點執行。
    在 Visual C++ 2005 之前,實值型別中的靜態建構函式 (型別初始設定式) 都是在該實值型別的執行個體建立時執行。若要確保執行靜態建構函式,請存取靜態資料成員或定義執行個體建構函式 (僅限使用 /clr:oldSyntax)。由於 Common Language Runtime 不一定每次都會呼叫預設的建構函式,因此不提供實值型別的預設建構函式。而且,不提供實值型別的預設建構函式也能改善效能。

  • 現在,Boxed 實值型別在可驗證的 (/clr:safe) 內容中是唯獨的。
    編譯可驗證的組件時,Common Language Runtime 不再允許修改 Boxed 實值型別。現在若偵測到這樣的狀況時,編譯器就會產生編譯器警告 C4972

    如果您經由 Boxed 值物件變更基礎值物件的值,就會發生 C4792 錯誤。如果您變更該值物件的複本 (例如,變更 Boxed 物件),就不會發生這個錯誤。

  • 原生型別預設在組件外為私用型別
    現在,預設在組件外看不到原生型別。如需組件外型別可視性的詳細資訊,請參閱Type Visibility。由於在參考以 Visual C++ 撰寫的中繼資料時,因應使用其他區分大小寫程式語言的程式開發人員所需,所以做了這項變更。

  • /clr 現在可以接受 Visual C++ 的新 CLR 語法
    在 Visual C++ 2005 之前,/clr 是編譯 Managed Extensions for C++ 語法。現在 /clr 則是編譯新的 CLR 語法;而 /clr:oldSyntax 則可以編譯 Managed Extensions for C++ 語法。如需 /clr 的詳細資訊,請參閱/clr (Common Language Runtime 編譯)。如需這個新語法的詳細資訊,請參閱Language Features for Targeting the CLR

  • /clr 不再編譯 C 原始程式碼檔
    在 Visual C++ 2005 之前,您可以搭配 /clr 編譯 C 原始程式碼檔,但是現在這麼做會導致命令列錯誤 D8045。 若要解決這個問題,請將副檔名變更為 .cpp 或 .cxx,或是搭配 /TP/Tp 進行編譯。如需詳細資訊,請參閱 /Tc、/Tp、/TC、/TP (指定原始程式檔類型)

  • 測試等式時的 MSIL 變更
    如需詳細資訊,請參閱 HOW TO:測試是否相等

請參閱

參考

Visual C++ 編譯器的重大變更