欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++之Primer類型轉(zhuǎn)換方式

 更新時間:2025年03月19日 08:38:11   作者:c-c-developer  
這篇文章主要介紹了C++之Primer類型轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

類型轉(zhuǎn)換

在C++語言中,某些類型之間有關(guān)聯(lián)。如果兩種類型有關(guān)聯(lián),那么當程序需要其中一種類型的運算對象時,可以用另一種關(guān)聯(lián)類型的對象或值來替代。

換句話說,如果兩種類型可以相互轉(zhuǎn)換(conversion),那么它們就是關(guān)聯(lián)的。

舉個例子,考慮下面這條表達式,它的目的是將ival初始化為6:

int ival = 3.541 + 3;//編譯器可能會警告該運算損失了精度

加法的兩個運算對象類型不同:3.541的類型是double,3的類型是int。C++語言不會直接將兩個不同類型的值相加,而是先根據(jù)類型轉(zhuǎn)換規(guī)則設(shè)法將運算對象的類型統(tǒng)一后再求值。上述的類型轉(zhuǎn)換是自動執(zhí)行的,無須程序員的介入,有時甚至不需要程序員了解。因此,它們被稱作隱式轉(zhuǎn)換(implicit conversion)。

算術(shù)類型之間的隱式轉(zhuǎn)換被設(shè)計得盡可能避免損失精度。很多時候,如果表達式中既有整數(shù)類型的運算對象也有浮點數(shù)類型的運算對象,整型會轉(zhuǎn)換成浮點型。在上面的例子中,3轉(zhuǎn)換成double類型,然后執(zhí)行浮點數(shù)加法,所得結(jié)果的類型是double。

接下來就要完成初始化的任務(wù)了。在初始化過程中,因為被初始化的對象的類型無法改變,所以初始值被轉(zhuǎn)換成該對象的類型。仍以這個例子說明,加法運算得到的double類型的結(jié)果轉(zhuǎn)換成int類型的值,這個值被用來初始化ival。由double向int轉(zhuǎn)換時忽略掉了小數(shù)部分,上面的表達式中,數(shù)值6被賦給了ival。

何時發(fā)生隱式類型轉(zhuǎn)換

在下面這些情況下,編譯器會自動地轉(zhuǎn)換運算對象的類型:

在大多數(shù)表達式中,比int類型小的整型值首先提升為較大的整數(shù)類型。在條件中,非布爾值轉(zhuǎn)換成布爾類型。初始化過程中,初始值轉(zhuǎn)換成變量的類型:在賦值語句中,右側(cè)運算對象轉(zhuǎn)換成左側(cè)運算對象的類型。如果算術(shù)運算或關(guān)系運算的運算對象有多種類型,需要轉(zhuǎn)換成同一種類型。函數(shù)調(diào)用時也會發(fā)生類型轉(zhuǎn)換。

算術(shù)轉(zhuǎn)換

算術(shù)轉(zhuǎn)換(arithmetic conversion)的含義是把一種算術(shù)類型轉(zhuǎn)換成另外一種算術(shù)類型。算術(shù)轉(zhuǎn)換的規(guī)則定義了一套類型轉(zhuǎn)換的層次,其中運算符的運算對象將轉(zhuǎn)換成最寬的類型。例如,如果一個運算對象的類型是long double,那么不論另外一個運算對象的類型是什么都會轉(zhuǎn)換成long double。還有一種更普遍的情況,當表達式中既有浮點類型也有整數(shù)類型時,整數(shù)值將轉(zhuǎn)換成相應(yīng)的浮點類型。

整型提升

整型提升(integral promotion)負責把小整數(shù)類型轉(zhuǎn)換成較大的整數(shù)類型。對于bool、char、signed char、unsigned char、short和unsigned short等類型來說,只要它們所有可能的值都能存在int里,它們就會提升成int類型,否則,提升成unsigned int類型。就如我們所熟知的,布爾值false提升成0、true提升成1。

較大的char類型(wchar_t、char16_t、vchar32_t)提升成int、unsigned int、long、unsigned long、long long和unsigned long long中最小的一種類型,前提是轉(zhuǎn)換后的類型要能容納原類型所有可能的值。

無符號類型的運算對象

如果樹個運算符的運算對象類型不一致,這些運算對象將轉(zhuǎn)換成同一種類型。但是如果樹個運算對象的類型是無符號類型,那么轉(zhuǎn)換的結(jié)果就要依賴于機器中各個整數(shù)類型的相對大小了。

像往常一樣,首先執(zhí)行整型提升。如果結(jié)果的類型匹配,無須進行進一步的轉(zhuǎn)換。如果兩個(提升后的運算對象的類型要么都是帶符號的、要么都是無符號的,則小類型的運算對象轉(zhuǎn)換成較大的類型。

如果一個運算對象是無符號類型、另外一個運算對象是帶符號類型,而一其中的無符號類型不小于帶符號類型,那么帶符號的運算對象轉(zhuǎn)換成無符號的。例如,假設(shè)兩個類型分別是unsigned int和int,則int類型的運算對象轉(zhuǎn)換成unsigned int類型。需要注意的是,如果int型的值恰好為負值。

剩下的一種情況是帶符號類型大于無符號類型,此時轉(zhuǎn)換的結(jié)果依賴于機器。如果無符號類型的所有值都能存在該帶符號類型中,則無符號類型的運算對象轉(zhuǎn)換成帶符號類型。如果不能,那么帶符號類型的運算對象轉(zhuǎn)換成無符號類型。例如,如果兩個運算對象的類型分別是long和unsigned int,并且int和long的大小相同,則long類型的運算對象轉(zhuǎn)換成unsigned int類型;如果long類型占用的空間比int更多,則unsigned int類型的運算對象轉(zhuǎn)換成long類型。

理解算術(shù)轉(zhuǎn)換

要想理解算術(shù)轉(zhuǎn)換,辦法之一就是研究大量的例子:

bool flag;char val;
short sval; unsigned short usval;
int ival; unsigned int uival;
long lval;unsigned long ulval;
float fval; double dval;
3.14159L+ 'a'; //“a“提升成int,然后該int值轉(zhuǎn)換成long double
dval+ival;//ival轉(zhuǎn)換成double
dval+fval;//fval轉(zhuǎn)換成double
ival=dval;//dval轉(zhuǎn)握成(切除小數(shù)部分后)int
flag=dval;//如果dval是0,則flag是false,否則f1ag是Lrue
cval+fval;//cval提升成int,然后該int值轉(zhuǎn)換成float
sval+cval;//sval和cval都提升成int
cval+lval;//cval轉(zhuǎn)援成long
ival+ulval;//ival轉(zhuǎn)換成unsigned long
usval+ival;//根據(jù)unsigned short和int所占空間的大小進行提升
uival+lval;//根據(jù)hnsigned int和long所占空間的大小進行轉(zhuǎn)換

在第一個加法運算中,小寫字母’a’是char型的字符常量,它其實能表示一個數(shù)字值。到底這個數(shù)字值是多少完全依賴于機器上的字符集,在我們的環(huán)境中,‘a’對應(yīng)的數(shù)字值是97。當把’a’ 和一個long double類型的數(shù)相加時,char類型的值首先提升成int類型,然后int類型的值再轉(zhuǎn)換成long double類型。最終我們把這個轉(zhuǎn)換后的值與那個字面值相加。最后的兩個含有無符號類型值的表達式也比較有趣,它們的結(jié)果依賴于機器。

其他隱式類型轉(zhuǎn)換運

除了算術(shù)轉(zhuǎn)換之外還有幾種隱式類型轉(zhuǎn)換,包括如下幾種。

數(shù)組轉(zhuǎn)換成指針:在大多數(shù)用到數(shù)組的表達式中,數(shù)組自動轉(zhuǎn)換成指向數(shù)組首元素的指針:

int ia[10];//含有10個整數(shù)的數(shù)組
int*ip = a;//ia轉(zhuǎn)換成指向數(shù)組首元素的指針

當數(shù)組被用作 decltype 關(guān)鍵字的參數(shù),或者作為取地址符(&)、sizeof及typeid等運算符的運算對象時,上述轉(zhuǎn)換不會發(fā)生。同樣的,如果用一個引用來初始化數(shù)組,上述轉(zhuǎn)換也不會發(fā)生。指針的轉(zhuǎn)換:C++還規(guī)定了幾種其他的指針轉(zhuǎn)換方式,包括常量整數(shù)值 0 或者字面值 nullptr 能轉(zhuǎn)換成任意指針類型;指向任意非常量的指針能轉(zhuǎn)換成void*;指向任意對象的指針能轉(zhuǎn)換成const void*。

型間還有另外一種指針轉(zhuǎn)換的方式。

轉(zhuǎn)換成布爾類型:存在一種從算術(shù)類型或指針類型向布爾類型自動轉(zhuǎn)換的機制。如果指針或算術(shù)類型的值為0,轉(zhuǎn)換結(jié)果是false;否則轉(zhuǎn)換結(jié)果是true:

char*cp=get_string();
if(cp) /*...*/ //如果指針cp不是0,條件為真
while(*cp)/*...*///如果*cp不是空字符,條件為真

轉(zhuǎn)換成常量:允許將指向非常量類型的指針轉(zhuǎn)換成指向相應(yīng)的常量類型的指針,對于引用也是這樣。也就是說,如果0是一種類型,我們就能將指向0的指針或引用分別轉(zhuǎn)換成指向const的指針或引用:

int i;

const int &j =i;  //非常量轉(zhuǎn)換成const int的引用
const int*p=&i;   //非常量的地址轉(zhuǎn)換成const的地址
int &r = j,*q= p; //錯誤:不允許const轉(zhuǎn)換成非常量

相反的轉(zhuǎn)換并不存在,因為它試圖刪除掉底層const。類類型定義的轉(zhuǎn)換:類類型能定義由編譯器自動執(zhí)行的轉(zhuǎn)換,不過編譯器每次只能執(zhí)行一種類類型的轉(zhuǎn)換。我們將看到一個例子,如果同時提出多個轉(zhuǎn)換請求,這些請求將被拒絕。

我們之前的程序已經(jīng)使用過類類型轉(zhuǎn)換:一處是在需要標準庫string類型的地方使用C風格守符串;另一處是在條件部分讀入istream:

string s, t= "a value";//字符串字面值轉(zhuǎn)換成string類型
while(cin >> s)       // while 的條件部分把cin 轉(zhuǎn)換成布爾值

條件( cin >> s )讀入cin的內(nèi)容并將cin作為其求值結(jié)果。條件部分本來需要一個布爾類型的值,但是這里實際檢查的是istream類型的值。幸好,IO庫定義了從istream向布爾值轉(zhuǎn)換的規(guī)則,根據(jù)這一規(guī)則,cin自動地轉(zhuǎn)換成布爾值。所得的布爾值到底是什么由輸入流的狀態(tài)決定,如果最后一次讀入成功,轉(zhuǎn)換得到的布爾值是true:相反,如果最后一次讀入不成功,轉(zhuǎn)換得到的布爾值是false。

顯式轉(zhuǎn)換

有時我們希望顯式地將對象強制轉(zhuǎn)換成另外一種類型。例如,如果想在下面的代碼中執(zhí)行浮點數(shù)除法:

int i,j;
double slope=i;

就要使用某種方法將i和/或j顯式地轉(zhuǎn)換成double,這種方法稱作強制類型轉(zhuǎn)換(cast)。

WARNING: 雖然有時不得不使用強制類型轉(zhuǎn)換,但這種方法本質(zhì)上是非常危險的。

命名的強制類型轉(zhuǎn)換

一個命名的強制類型轉(zhuǎn)換具有如下形式:

cast-name<type>(expression)

其中,type是轉(zhuǎn)換的目標類型而 expression 是要轉(zhuǎn)換的值。如果type是引用類型,則結(jié)果是左值。cast-name是 static_cast、dynamic_cast、const_cast 和reinterpret_cast中的一種。dynamic_cast支持運行時類型識別。

static_cast

任何具有明確定義的類型轉(zhuǎn)換,只要不包含底層const,都可以使用static_cast。例如,通過將一個運算對象強制轉(zhuǎn)換成double類型就能使表達式執(zhí)行浮點數(shù)除法:

//進行強制類型轉(zhuǎn)換以便執(zhí)行浮點數(shù)除法
double slope=static_cast<double>(j)/i; 

當需要把一個較大的算術(shù)類型賦值給較小的類型時,static_cast非常有用。此時,強制類型轉(zhuǎn)換告訴程序的讀者和編譯器:我們知道并且不在乎潛在的精度損失。一般來說,如果編譯器發(fā)現(xiàn)一個較大的算術(shù)類型試圖賦值給較小的類型,就會給出警告信息;但是當我們執(zhí)行了顯式的類型轉(zhuǎn)換后,警告信息就會被關(guān)閉了。

static_cast對于編詳器無法自動執(zhí)行的類型轉(zhuǎn)換也非常有用。例如,我們可以使用static_cast找回存在于void*指針中的值:

void+p=&d;//正確:任何非常量對象的地址都能存入void*
          //正確:將void*轉(zhuǎn)接回初始的指針類型
double*dp=static_cast<double*>(p);

當我們把指針存放在void*中,并且使用static_cast將其強制轉(zhuǎn)換回原來的類型時,應(yīng)該確保指針的值保持不變。也就是說,強制轉(zhuǎn)換的結(jié)果將與原始的地址值相等,因此我們必須確保轉(zhuǎn)換后所得的類型就是指針所指的類型。類型一旦不符,將產(chǎn)生未定義的后果。

const_cast

const_cast只能改變運算對象的底層const:

const char*pc;
char*p=const_cast<char*>(pc);//正確:但是通過p寫值是未定義的行為

對于將常量對象轉(zhuǎn)換成非常量對象的行為,我們一般稱其為“去掉const性質(zhì)(cast away the const)“。一旦我們?nèi)サ袅藰鋫€對象的const性質(zhì),編譯器就不再阻止我們對該對象進行寫操作了。如果對象本身不是一個常量,使用強制類型轉(zhuǎn)換獲得寫權(quán)限是合法的行為。然而如果對象是一個常量,再使用const_cast執(zhí)行寫操作就會產(chǎn)生未定義的后果。

只有const_cast能改變表達式的常量屬性,使用其他形式的命名強制類型轉(zhuǎn)換改變表達式的常量屬性都將引發(fā)編譯器錯誤。同樣的,也不能用const_cast改變表達式的類型:

const char*cp;
//錯誤:static_cast不能轉(zhuǎn)換據(jù)const性質(zhì)
char*q = static_cast<char*>(cp);
static_cast<string>(cp);//正確:字符串字面值轉(zhuǎn)換成string類型
const_cast<string>(cp);//錯誤:const_cast只改變常量屬性

const_cast常常用于有函數(shù)重載的上下文中

reinterpret_cast

reinterpret_cast通常為運算對象的位模式提供較低層次上的重新解釋。舉個例子,假設(shè)有如下的轉(zhuǎn)換

int *ip;
char*pc=reinterpret_cast<char*>(ip);

我們必須牢記pc所指的真實對象是一個int而非字符,如果把pc當成普通的字符指針使用就可能在運行時發(fā)生錯誤。例如:

string str(pc);

可能導致異常的運行時行為。

使用reinterpret_cast是非常危險的,用pc初始化str的例子很好地證明了這一點。其中的關(guān)鍵問題是類型改變了,但編譯器沒有給出任何警告或者錯誤的提示信息。當我們用一個int的地址初始化pc時,由于顯式地聲稱這種轉(zhuǎn)換合法,所以編譯器不會發(fā)出任何警告或錯誤信息。接下來再使用pc時就會認定它的值是char*類型,編譯器沒法知道它實際存放的是指向int的指針。最終的結(jié)果就是,在上面的例子中雖然用pc初始化str沒什么實際意義,甚至還可能引發(fā)更糟糕的后果,但僅從語法上而言這種操作無可指摘。查找這類問題的原因非常困難,如果將ip強制轉(zhuǎn)換成pc的語句和用pc初始化string對象的語句分屬不同文件就更是如此。

WRNING: reinterpret_cast本質(zhì)上依賴于機器.要想安全地使用reinterpret_cast必須對涉及的類型和編譯囂實現(xiàn)轉(zhuǎn)換的過程都非常了解。

建議:避免強制類型轉(zhuǎn)換

強制類型轉(zhuǎn)換干擾了正常的類型檢查,因此我們強烈建議程序員避免使用強制類型轉(zhuǎn)換。這個建議對于reinterpret_cast尤其適用,因為此類類型轉(zhuǎn)換總是充滿了風險。在有重載函數(shù)的上下文中使用const_cast無可厚非,關(guān)于這一點將在;但是在其他情況下使用const_cast也就意味著程序存在某種設(shè)計缺陷。其他強制類型轉(zhuǎn)換,比如static_cast和dynamic_cast,都不應(yīng)該頻素使用。每次書寫了一條強制類型轉(zhuǎn)換語句,都應(yīng)該反復斟酌能否以其他方式實現(xiàn)相同的目標。就算實在無法避免,也應(yīng)該盡量限制類型轉(zhuǎn)換值的作用域,并且記錄對相關(guān)類型的所有假定,這樣可以減少錯誤發(fā)生的機會。′

舊式的強制類型轉(zhuǎn)換

在早期版本的C++語言中,顯式地進行強制類型轉(zhuǎn)換包含兩種形式:

type(expr);//函數(shù)形式的強制類型轉(zhuǎn)換
(type)expr;//C語言風格的強制類型轉(zhuǎn)換

根據(jù)所涉及的類型不同,舊式的強制類型轉(zhuǎn)換分別具有與const_cast、static_cast或reinterpret_cast相似的行為。當我們在某處執(zhí)行舊式的強制類型轉(zhuǎn)換時,如果換成const_cast和static_cast也合法,則其行為與對應(yīng)的命名轉(zhuǎn)換一致。如果替換后不合法,則舊式強制類型轉(zhuǎn)換執(zhí)行與reinterpret_cast類似的功能:

char *pc=(char*)ip;//ip是指向整數(shù)的指針

的效果與使用retnterpret_cast一樣。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于C語言實現(xiàn)貪吃蛇小游戲

    基于C語言實現(xiàn)貪吃蛇小游戲

    這篇文章主要為大家詳細介紹了基于C語言實現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言銀行系統(tǒng)課程設(shè)計

    C語言銀行系統(tǒng)課程設(shè)計

    這篇文章主要為大家詳細介紹了C語言銀行系統(tǒng)課程設(shè)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++二進制翻轉(zhuǎn)實例分析

    C++二進制翻轉(zhuǎn)實例分析

    這篇文章主要介紹了C++二進制翻轉(zhuǎn),通過幾個實例分析二進制翻轉(zhuǎn)算法的實現(xiàn)技巧,需要的朋友可以參考下
    2014-09-09
  • C++ 中的INT_MAX,INT_MIN數(shù)值大小操作

    C++ 中的INT_MAX,INT_MIN數(shù)值大小操作

    這篇文章主要介紹了C++ 中的INT_MAX,INT_MIN數(shù)值大小操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • VSCODE+cmake配置C++開發(fā)環(huán)境的實現(xiàn)步驟

    VSCODE+cmake配置C++開發(fā)環(huán)境的實現(xiàn)步驟

    這篇文章主要介紹了VSCODE+cmake配置C++開發(fā)環(huán)境的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • 詳細聊聊c語言中的緩沖區(qū)問題

    詳細聊聊c語言中的緩沖區(qū)問題

    緩沖區(qū)又稱為緩存,它是內(nèi)存空間的一部分,也就是說在內(nèi)存空間中預留了一定的存儲空間,這些存儲空間用來緩沖輸入或輸出的數(shù)據(jù),這部分預留的空間就叫做緩沖區(qū),這篇文章主要給大家介紹了關(guān)于c語言中緩沖區(qū)問題的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • C++ 將字符串值賦給CHAR數(shù)組的實現(xiàn)

    C++ 將字符串值賦給CHAR數(shù)組的實現(xiàn)

    這篇文章主要介紹了C++ 將字符串值賦給CHAR數(shù)組的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • C++保存HBITMAP為位圖文件的實現(xiàn)方法

    C++保存HBITMAP為位圖文件的實現(xiàn)方法

    這篇文章主要介紹了C++保存HBITMAP為位圖文件的實現(xiàn)方法,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下
    2021-01-01
  • c語言實現(xiàn)從源文件從文本到可執(zhí)行文件經(jīng)歷的過程

    c語言實現(xiàn)從源文件從文本到可執(zhí)行文件經(jīng)歷的過程

    這篇文章主要介紹了c語言實現(xiàn)從源文件從文本到可執(zhí)行文件經(jīng)歷的過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++ 互斥鎖原理以及實際使用介紹

    C++ 互斥鎖原理以及實際使用介紹

    本文主要聊一聊如何使用互斥鎖以及都有哪幾種方式實現(xiàn)互斥鎖。實現(xiàn)互斥,可以有以下幾種方式:互斥量(Mutex)、遞歸互斥量(Recursive Mutex)、讀寫鎖(Read-Write Lock)、條件變量(Condition Variable)。感興趣的同學可以參考一下
    2023-04-04

最新評論