C++11 與 C99的相容
阿新 • • 發佈:2019-01-28
C++對以下C99特性的支援納入了新標準之中:
1、C99中的預定義巨集
2、__func__預定義識別符號
3、_Pragma操作符
4、不定引數巨集定義以及__VA_ARGS__
5、寬窄字串連線
使用上述巨集可以檢查機器環境對C標準和C庫的支援情況。
Tips: vs2012中不支援,g++ 3.3.2版本支援,這個版本的g++還不支援C++11標準。所以這是相容C99標準。
__func__在按照標準定義,編譯器會隱式地在函式定義後面定義__func__識別符號。
在C++11標準中,還允許在類和結構體中使用這個巨集。
但是將__func__識別符號作為函式引數的預設值是不允許的。
void FuncFail(string func_name = __func__){}; //編譯不能通過
#pragma once
上述程式碼和
C++11中定義一個_Pragma操作符和#pragma作用相同。_Pragma操作符的格式如下:
_Pragma(字串字面量)
使用_Pragma操作符想要達到#pragma once的效果可以:
_Pragma("once")
#define PR(...) printf(__VA__ARGS__)
就可以定義一個printf的別名PR。事實上,變長引數巨集和printf是一對好搭檔。
上述例子在vs2012中不支援,在g++ 3.3.2版本支援
可靠的對兩種型別的目標檔案進行連線,這樣該做法成為C與C++混用標頭檔案的典型做法。
tips:在C++03標準中,__cplusplus的值被預定為199711L,在C++11中,巨集__cplusplus被預定義成201103L。那麼可以利用這個巨集來檢查編譯器是否支援C++11新標準。
這裡,使用了預處理指令#error,使得不支援C++11時,編譯報錯並且終止編譯。
3、斷言assert
assert是一種邊程式設計中常用的手段。用於排除在邏輯上不應該產生的情況。在C++中標準在<cassert>或者<assert.h>標頭檔案中為程式設計師提供了assert巨集,用於在執行時進行斷言。
static_assert在C++11中定義了一個static_assert,這個宣告對於模板的除錯非常有用,編譯器快速執行這個常量表示式引數(不能依賴模板引數)。否則編譯器當模板例項化時執行這個常量表達式的引數。
1、C99中的預定義巨集
2、__func__預定義識別符號
3、_Pragma操作符
4、不定引數巨集定義以及__VA_ARGS__
5、寬窄字串連線
1> c++11中與c99相容的巨集如下表所示:
使用上述巨集可以檢查機器環境對C標準和C庫的支援情況。
在g++ 2.3.3版本中後面兩行不能編譯通過,說明在g++ 2.3.3版本中可能沒有給出這兩個巨集的定義。#include <iostream> using namespace std; int main() { cout << "Standerd Clib" << __STDC_HOSTED__ << endl; cout << "Standerd C" << __STDC__ << endl; //cout << "C Standerd version " << __STDC_VERSION__ << endl; //cout << "ISO/IEC" << __STDC_ISO_10646__ << endl; return 0; }
2> __func__預定義識別符號
很多現實的編譯器都支援C99標準中的__func__預定義識別符號功能,其基本功能就是返回所在函式的名字。#include <iostream> using namespace std; const char* hello() { return __func__; } const char* world() { return __func__; } int main() { cout << hello() << world() << endl; return 0; }
Tips: vs2012中不支援,g++ 3.3.2版本支援,這個版本的g++還不支援C++11標準。所以這是相容C99標準。
__func__在按照標準定義,編譯器會隱式地在函式定義後面定義__func__識別符號。
const char* hello()
{
static const char* __func__ = "hello";
renturn __func__;
}
在C++11標準中,還允許在類和結構體中使用這個巨集。
#include <iostream> using namespace std; struct TestStruct { TestStruct(): name(__func__) { } const char* name; }; int main() { TestStruct ts; cout << ts.name << endl; renturn 0; }
但是將__func__識別符號作為函式引數的預設值是不允許的。
void FuncFail(string func_name = __func__){}; //編譯不能通過
3>_Pragma操作符
在C/C++標準中,#pragma是一條預處理指令。#pragma once
上述程式碼和
#ifndef THIS_HEADER
#define THIS_HEADER
//一些標頭檔案定義
#endif
C++11中定義一個_Pragma操作符和#pragma作用相同。_Pragma操作符的格式如下:
_Pragma(字串字面量)
使用_Pragma操作符想要達到#pragma once的效果可以:
_Pragma("once")
4>變長引數的巨集定義以及__VA_ARGS__
在C99標準中,程式設計師可以使用變長引數的巨集定義。變長引數的巨集定義是指在巨集定義中引數列表的最後一個引數為省略號,而預定義巨集__VA_ARGS__則可以在巨集定義的實現部分替換省略號所代表的字串。#define PR(...) printf(__VA__ARGS__)
就可以定義一個printf的別名PR。事實上,變長引數巨集和printf是一對好搭檔。
#include <stdio.h>
#define LOG(...) {\
fprintf(stderr,"%S:Line %d:\t"), __FILE__, __LINE__};\
fprintf(stderr,__VA__ARGS__);\
fprintf(stderr,"\n");\
}
int main()
{
int x=3;
LOG("x=%d",x);
}
上述例子在vs2012中不支援,在g++ 3.3.2版本支援
5>寬窄字串連線
在C++11中,在將窄字串和寬字串進行連線時,支援C++11標準的編譯器會將窄字串轉換成寬字串,然後再與寬字串進行連線。6、擴充套件的整型
C++11中一共只定義了5種標準的有符號整型:
signed char
short int
int
long int
long long int
標準同時規定,每一種有符號整型都有一種對應的無符號整型版本,而且有符號整型與其對應的無符號整型具有相同的儲存空間大小。
7、巨集__cplusplus
在C/C++混合編寫的程式碼中,我們經常會在標頭檔案中看到如下的宣告:
#ifdef __cplusplus
extern "C"{
#endif
//一些程式碼
#ifdef __cplusplus
}
#endif
由於extern "C"可以抑制C++對函式名、變數名等符號進行名稱重整(name mangling),因此編譯出的C目標檔案中的變數,函式名稱等等符號都是相同的,聯結器可以可靠的對兩種型別的目標檔案進行連線,這樣該做法成為C與C++混用標頭檔案的典型做法。
tips:在C++03標準中,__cplusplus的值被預定為199711L,在C++11中,巨集__cplusplus被預定義成201103L。那麼可以利用這個巨集來檢查編譯器是否支援C++11新標準。
#if __cplusplus < 20131103L
#error "should use C++ 11 implementation"
#endif
這裡,使用了預處理指令#error,使得不支援C++11時,編譯報錯並且終止編譯。
3、斷言assert
assert是一種邊程式設計中常用的手段。用於排除在邏輯上不應該產生的情況。在C++中標準在<cassert>或者<assert.h>標頭檔案中為程式設計師提供了assert巨集,用於在執行時進行斷言。
#include <cassert>
using namespace std;
double div(double a,double b)
{
assert(b != 0.000000); //斷言除數必須不為零
return a/b;
}
int main()
{
double rt = div(10,0);
return 0;
}
static_assert在C++11中定義了一個static_assert,這個宣告對於模板的除錯非常有用,編譯器快速執行這個常量表示式引數(不能依賴模板引數)。否則編譯器當模板例項化時執行這個常量表達式的引數。
#include <cassert>
#include <cstring>
using namespace std;
template<typename t, typename u>
int bit_copy(t& a, u& b)
{
static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have same width.");
};
int main() {
int a = 0x2468;
double b;
bit_copy(a,b);
return 0;
}
在編譯的過程中就會出現如下的錯誤資訊: