首頁 > 軟體

C++11中longlong超長整型和nullptr初始化空指標

2022-12-31 14:01:08

本文介紹 C++11 標準中新新增的 long long 超長整型和 nullptr 初始化空指標。

1. C++11:long long 超長整型

C++ 11 標準中,基於整數大小的考慮,共提供瞭如下表所示的這些資料型別。與此同時,標準中還明確限定了各個資料型別最少佔用的位數。

整數型別等價型別C++11標準規定佔用最少位數
shortshort int(有符號短整型)至少 16 位(2 個位元組)
signed shortshort int(有符號短整型)至少 16 位(2 個位元組)
signed short intshort int(有符號短整型)至少 16 位(2 個位元組)
unsigned shortunsigned short int(無符號短整型)至少 16 位(2 個位元組)
unsigned short intunsigned short int(無符號短整型)至少 16 位(2 個位元組)
intint(有符號整形)至少 16 位(2 個位元組)
signedint(有符號整形)至少 16 位(2 個位元組)
signed intint(有符號整形)至少 16 位(2 個位元組)
unsignedunsigned int(無符號整形)至少 16 位(2 個位元組)
unsigned intunsigned int(無符號整形)至少 16 位(2 個位元組)
longlong int(有符號長整形)至少 32 位(4 個位元組)
long intlong int(有符號長整形)至少 32 位(4 個位元組)
signed longlong int(有符號長整形)至少 32 位(4 個位元組)
signed long intlong int(有符號長整形)至少 32 位(4 個位元組)
unsigned longunsigned long int(無符號長整形)至少 32 位(4 個位元組)
unsigned long intunsigned long int(無符號長整形)至少 32 位(4 個位元組)
long long(C++11)long long int(有符號超長整形)至少 64 位(8 個位元組)
long long int(C++11)long long int(有符號超長整形)至少 64 位(8 個位元組)
signed long long(C++11)long long int(有符號超長整形)至少 64 位(8 個位元組)
signed long long int(C++11)long long int(有符號超長整形)至少 64 位(8 個位元組)
unsigned long long(C++11)unsigned long long int(無符號超長整型)至少 64 位(8 個位元組)
unsigned long long int(C++11)unsigned long long int(無符號超長整型)至少 64 位(8 個位元組)

C++11 標準規定,每種整數型別必須同時具備有符號(signed)和無符號(unsigned)兩種型別,且每種具體的有符號整形和無符號整形所佔用的儲存空間(也就是位數)必須相同。不過需要注意的是,C++11 標準中只限定了每種型別最少佔用多少儲存空間,不同的平臺可以佔用不同的儲存空間。

在上表羅列的這些資料型別中,long long 超長整型是 C++ 11 標準新新增的。其實早在 1995 年,就有人提議將 long long 整形寫入 C++ 98 標準,但被委員會拒絕了。而後 long long 整形被 C99 標準(C語言標準之一)採納,並逐漸被很多編譯器支援,於是 C++ 標準委員會重新決定將 long long 整形寫入 C++ 11 標準中。

如同 long 型別整數需明確標註 "L" 或者 "l" 字尾一樣,要使用 long long 型別的整數,也必須標註對應的字尾:

  • 對於有符號 long long 整形,字尾用 "LL" 或者 "ll" 標識。例如,"10LL" 就表示有符號超長整數 10;
  • 對於無符號 long long 整形,字尾用 "ULL"、"ull"、"Ull" 或者 "uLL" 標識。例如,"10ULL" 就表示無符號超長整數 10。

如果不新增任何標識,則所有的整數都會預設為 int 型別。

對於 long long 型別來說,如果想了解當前平臺上 long long 整形的取值範圍,可以使用<climits>標頭檔案中與 long long 整形相關的 3 個宏,分別為 LLONG_MIN、LLONG_MAX 和 ULLONG_MIN:
1)LLONG_MIN:代表當前平臺上最小的 long long 型別整數;
2)LLONG_MAX:代表當前平臺上最大的 long long 型別整數;
3)ULLONG_MIN:代表當前平臺上最大的 unsigned long long 型別整數(無符號超長整型的最小值為 0)。
舉個例子:

#include <iostream>
#include <iomanip>
#include <climits>
using namespace std;

int main()
{
    cout <<"long long最大值:" << LLONG_MIN <<" "<< hex << LLONG_MIN <<"n";
    cout << dec <<"long long最小值:" << LLONG_MAX << " " << hex << LLONG_MAX << "n";
    cout << dec << "unsigned long long最大值:" << ULLONG_MAX << " " << hex << ULLONG_MAX;
    return 0;
}

程式執行結果為(不唯一):

long long最大值:-9223372036854775808 8000000000000000
long long最小值:9223372036854775807 7fffffffffffffff
unsigned long long最大值:18446744073709551615 ffffffffffffffff

此程式中,輸出了各最大值和最小值對應的十六進位制,顯然在當前平臺(Windows10 64位元作業系統)上,long long 超長整型佔用 64 位(也就是 16 個位元組)的儲存空間。

2. C++11:nullptr 初始化空指標

實際開發中,避免產生“野指標”最有效的方法,就是在定義指標的同時完成初始化操作,即便該指標的指向尚未明確,也要將其初始化為空指標。

所謂“野指標”,又稱“懸掛指標”,指的是沒有明確指向的指標。野指標往往指向的是那些不可用的記憶體區域,這就意味著像操作普通指標那樣使用野指標(例如 &p),極可能導致程式發生異常。

C++98/03 標準中,將一個指標初始化為空指標的方式有 2 種:

int *p = 0;
int *p = NULL; //推薦使用

可以看到,我們可以將指標明確指向 0(0x0000 0000)這個記憶體空間。一方面,明確指標的指向可以避免其成為野指標;另一方面,大多數作業系統都不允許使用者對地址為 0 的記憶體空間執行寫操作,若使用者在程式中嘗試修改其內容,則程式執行會直接報錯。
相比第一種方式,我們更習慣將指標初始化為 NULL。值得一提的是,NULL 並不是 C++ 的關鍵字,它是 C++ 為我們事先定義好的一個宏,並且它的值往往就是字面量 0(#define NULL 0)。

C++ 中將 NULL 定義為字面常數 0,雖然能滿足大部分場景的需要,但個別情況下,它會導致程式的執行和我們的預期不符。例如:

#include <iostream>
using namespace std;

void isnull(void *c){
    cout << "void*c" << endl;
}
void isnull(int n){
    cout << "int n" << endl;
}

int main() {
    isnull(0);
    isnull(NULL);
    return 0;
}

程式執行結果為:

int n
int n

對於 isnull(0) 來說,顯然它真正呼叫的是引數為整形的 isnull() 函數;而對於 isnull(NULL),我們期望它實際呼叫的是引數為 void*c 的 isnull() 函數,但觀察程式的執行結果不難看出,並不符合我們的預期。
C++ 98/03 標準中,如果我們想令 isnull(NULL) 實際呼叫的是 isnull(void* c),就需要對 NULL(或者 0)進行強制型別轉換:

isnull( (void*)NULL );
isnull( (void*)0 );

如此,才會成功呼叫我們預期的函數。

由於 C++ 98 標準使用期間,NULL 已經得到了廣泛的應用,出於相容性的考慮,C++11 標準並沒有對 NULL 的宏定義做任何修改。為了修正 C++ 存在的這一 BUG,C++ 標準委員會最終決定另其爐灶,在 C++11 標準中引入一個新關鍵字,即 nullptr。

在使用 nullptr 之前,需保證自己使用的編譯器支援該關鍵字。以 Visual Studio 和 codeblocks 為例,前者早在 2010 版本就對 C++ 11 標準中的部分特性提供了支援,其中就包括 nullptr;如果使用後者,則需將其 G++ 編譯器版本至少升級至 4.6.1(同時開啟 -std=c++0x 編譯選項)。

nullptr 是 nullptr_t 型別的右值常數,專用於初始化空型別指標。nullptr_t 是 C++11 新增加的資料型別,可稱為“指標空值型別”。也就是說,nullpter 僅是該型別的一個範例物件(已經定義好,可以直接使用),如果需要我們完全定義出多個同 nullptr 完全一樣的範例物件。

值得一提的是,nullptr 可以被隱式轉換成任意的指標型別。舉個例子:

int * a1 = nullptr;
char * a2 = nullptr;
double * a3 = nullptr;

顯然,不同型別的指標變數都可以使用 nullptr 來初始化,編譯器分別將 nullptr 隱式轉換成 int*、char* 以及 double* 指標型別。

另外,通過將指標初始化為 nullptr,可以很好地解決 NULL 遺留的問題,比如:

#include <iostream>
using namespace std;

void isnull(void *c){
    cout << "void*c" << endl;
}
void isnull(int n){
    cout << "int n" << endl;
}

int main() {
    isnull(NULL);
    isnull(nullptr);
    return 0;
}

程式執行結果為:

int n
void*c

藉助執行結果不難看出,由於 nullptr 無法隱式轉換為整形,而可以隱式匹配指標型別,因此執行結果和我們的預期相符。

總之在 C++11 標準下,相比 NULL 和 0,使用 nullptr 初始化空指標可以令我們編寫的程式更加健壯。

到此這篇關於C++11:longlong超長整型和nullptr初始化空指標的文章就介紹到這了,更多相關C++11 nullptr初始化空指標內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com