?
Ce document utilise Manuel du site Web PHP chinois Libérer
當(dāng)預(yù)期在不同類型的值的上下文中使用表達(dá)式時(shí),可能會(huì)發(fā)生轉(zhuǎn)換:
int n = 1L; // expression 1L has type long, int is expectedn = 2.1; // expression 2.1 has type double, int is expectedchar *p = malloc(10); // expression malloc(10) has type void*, char* is expected
轉(zhuǎn)換發(fā)生在以下情況:
在賦值運(yùn)算符中,右側(cè)操作數(shù)的值被轉(zhuǎn)換為左側(cè)操作數(shù)的非限定類型。
在標(biāo)量初始化中,初始化表達(dá)式的值被轉(zhuǎn)換為被初始化的對(duì)象的非限定類型
在函數(shù)調(diào)用表達(dá)式中,對(duì)于具有原型的函數(shù),將每個(gè)參數(shù)表達(dá)式的值轉(zhuǎn)換為相應(yīng)參數(shù)的非限定聲明類型
在return語句中,操作數(shù)的值return
被轉(zhuǎn)換為具有函數(shù)返回類型的對(duì)象
請(qǐng)注意,除轉(zhuǎn)換外,實(shí)際分配也會(huì)從浮點(diǎn)類型中移除額外的范圍和精度,并禁止重疊; 這些特性不適用于轉(zhuǎn)換,就像通過分配一樣。
在調(diào)用時(shí)的函數(shù)調(diào)用表達(dá)式中。
1)沒有原型的功能
2)可變參數(shù)函數(shù),其中參數(shù)表達(dá)式是與省略號(hào)參數(shù)匹配的尾隨參數(shù)之一
整數(shù)類型的每個(gè)參數(shù)都經(jīng)過整數(shù)提升(參見下文),并且每個(gè)類型的參數(shù)都float
被隱式轉(zhuǎn)換為類型double
。
int add_nums(int count, ...);int sum = add_nums(2, 'c', true); // add_nums is called with three ints: (2, 99, 1)
請(qǐng)注意,float
complex
和float
imaginary
沒有提升到double
complex
和double
imaginary
在這種情況下。
以下算術(shù)運(yùn)算符的參數(shù)經(jīng)過隱式轉(zhuǎn)換,以獲得公共實(shí)數(shù)類型,這是執(zhí)行計(jì)算的類型:
二進(jìn)制算術(shù)*,/,%,+, -
關(guān)系運(yùn)算符<,>,<=,> =,==,!=
二進(jìn)制按位運(yùn)算&,^,|,
條件操作符?:
1)如果一個(gè)操作數(shù)是long double
,long
double
complex
或long
double
imaginary
,另一個(gè)操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)或?qū)嶋H浮動(dòng)類型 long double
復(fù)雜類型 long
double
complex
虛構(gòu)類型 long
double
imaginary
2)否則,如果一個(gè)操作數(shù)是double
,double
complex
或double
imaginary
,另一個(gè)操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)或?qū)嶋H浮動(dòng)類型 double
復(fù)雜類型 double
complex
虛構(gòu)類型 double
imaginary
3)否則,如果一個(gè)操作數(shù)是float
,float
complex
或float
imaginary
,另一個(gè)操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)類型為float
(唯一可能的實(shí)際類型是float,保持原樣)
復(fù)雜類型依然存在 float
complex
虛構(gòu)類型仍然存在 float
imaginary
4)否則,兩個(gè)操作數(shù)都是整數(shù)。在這種情況下,首先,兩個(gè)操作數(shù)都進(jìn)行整數(shù)升級(jí)(見下文)。然后
如果促銷后的類型相同,則該類型是常見類型
否則,如果促銷后的兩個(gè)操作數(shù)具有相同的簽名(均為有符號(hào)或無符號(hào)),則具有較低轉(zhuǎn)換等級(jí)的操作數(shù)(請(qǐng)參見下文)會(huì)隱式轉(zhuǎn)換為具有較高轉(zhuǎn)換等級(jí)的操作數(shù)的類型
否則,簽名會(huì)有所不同:如果具有無符號(hào)類型的操作數(shù)的轉(zhuǎn)換等級(jí)大于或等于有符號(hào)操作數(shù)類型的等級(jí),則帶符號(hào)類型的操作數(shù)將隱式轉(zhuǎn)換為無符號(hào)類型
否則,簽名是不同的,并且?guī)Х?hào)的操作數(shù)的等級(jí)大于無符號(hào)的操作數(shù)的等級(jí)。在這種情況下,如果有符號(hào)類型可以表示所有無符號(hào)類型的值,那么具有無符號(hào)類型的操作數(shù)將隱式轉(zhuǎn)換為有符號(hào)操作數(shù)的類型。
否則,兩個(gè)操作數(shù)都會(huì)隱式轉(zhuǎn)換為帶符號(hào)操作數(shù)類型的無符號(hào)類型。
1.f + 20000001; // int is converted to float, giving 20000000.00 // addition and then rounding to float gives 20000000.00(char)'a' + 1L; // First, char is promoted back to int. // this is signed + signed case, different rank // int is converted to long, the result is 98 signed long2u - 10; // signed / unsigned, same rank // 10 is converted to unsigned, unsigned math is modulo UINT_MAX+1 // assuming 32 bit ints, result is 4294967288 of type unsigned int (aka UINT_MAX-7)0UL - 1LL; // signed/unsigned diff rank, rank of signed is greater. // If sizeof(long) == sizeof(long long), signed cannot represent all unsigned // this is the last case: both operands are converted to unsigned long long // the result is 18446744073709551615 (ULLONG_MAX) of type unsigned long long
結(jié)果類型確定如下:
如果兩個(gè)操作數(shù)都很復(fù)雜,則結(jié)果類型很復(fù)雜
如果兩個(gè)操作數(shù)都是虛構(gòu)的,則結(jié)果類型是虛構(gòu)的
如果兩個(gè)操作數(shù)都是實(shí)數(shù),則結(jié)果類型是實(shí)數(shù)
如果兩個(gè)浮點(diǎn)操作數(shù)具有不同的類型域(復(fù)數(shù)與實(shí)數(shù),復(fù)數(shù)與虛數(shù),或虛數(shù)與實(shí)數(shù)),則結(jié)果類型很復(fù)雜
double complex z = 1 + 2*I;double f = 3.0;z + f; // z remains as-is, f is converted to double, the result is double complex
與往常一樣,浮點(diǎn)運(yùn)算符的結(jié)果可能比其類型所指示的范圍和精度更高(請(qǐng)參閱參考資料FLT_EVAL_METHOD
)。
注意:實(shí)數(shù)和虛數(shù)操作數(shù)不會(huì)隱式轉(zhuǎn)換為復(fù)數(shù),因?yàn)檫@樣做需要額外的計(jì)算,而在涉及無窮大,NaN和帶符號(hào)的零的某些情況下會(huì)產(chǎn)生不希望的結(jié)果。例如,如果將實(shí)數(shù)轉(zhuǎn)換為復(fù)數(shù),則2.0×(3.0 +i∞)將評(píng)估為(2.0 + i0.0)×(3.0 +i∞)?(2.0×3.0-0.0×∞)+ i(2.0× ∞+ 0.0×3.0)?NaN +i∞而不是正確的6.0 +i∞。如果虛數(shù)轉(zhuǎn)換為復(fù)數(shù),則i2.0×(∞+ i3.0)將評(píng)估為(0.0 + i2.0)×(∞+ i3.0)?(0.0×∞ - 2.0×3.0)+ i(0.0 ×3.0 + 2.0×∞)?NaN +i∞而不是-6.0 +i∞。
注意:無論通常的算術(shù)轉(zhuǎn)換如何,在as-if規(guī)則下,通過這些規(guī)則,計(jì)算總是可以以窄于指定符的類型執(zhí)行。
任何非數(shù)組類型的任何左值表達(dá)式,當(dāng)在除。以外的任何上下文中使用時(shí)。
作為操作符的操作數(shù)(如果允許)
作為前/后增量和減量運(yùn)算符的操作數(shù)。
作為成員訪問(點(diǎn))運(yùn)算符的左側(cè)操作數(shù)。
作為賦值和復(fù)合賦值操作符的左側(cè)操作數(shù)。
作為 sizeof 的操作數(shù)
進(jìn)行左值轉(zhuǎn)換:類型保持不變,但會(huì)丟失 const / volatile / restrict-qualifiers 和原子屬性(如果有的話)。價(jià)值保持不變,但失去了左值屬性(地址可能不再被采用)。
如果左值具有不完整類型,則行為未定義。
如果左值指定一個(gè)自動(dòng)存儲(chǔ)持續(xù)時(shí)間的對(duì)象,其地址從未被采用,并且該對(duì)象未初始化(未使用初始化器聲明并且在使用之前未對(duì)其進(jìn)行分配),則行為是未定義的。
此轉(zhuǎn)換將模擬對(duì)象的值從其位置的內(nèi)存負(fù)載。
volatile int n = 1;int x = n; // lvalue conversion on n reads the value of nvolatile int* p = &n; // no lvalue conversion: does not read the value of n
數(shù)組類型的任何左值表達(dá)式,當(dāng)在除。以外的任何上下文中使用時(shí)。
作為操作符地址的操作數(shù)
作為 sizeof 的操作數(shù)
作為用于數(shù)組初始化的字符串文字
經(jīng)歷轉(zhuǎn)換到非左值指針到它的第一個(gè)元素。
如果數(shù)組被聲明為注冊(cè),則行為是未定義的。
int a[3], b[3][4];int* p = a; // conversion to &a[0]int (*q)[4] = b; // conversion to &b[0]
任何函數(shù)指示符表達(dá)式,當(dāng)在除。以外的任何上下文中使用時(shí)。
作為操作符地址的操作數(shù)
作為sizeof的操作數(shù)
經(jīng)過轉(zhuǎn)換到非左值指針指向由表達(dá)式指定的函數(shù)。
int f(int);int (*p)(int) = f; // conversion to &f(***p)(1); // repeated dereference to f and conversion back to &f
隱式轉(zhuǎn)換,無論是通過賦值還是通常的算術(shù)轉(zhuǎn)換,都由兩個(gè)階段組成:
1)價(jià)值轉(zhuǎn)化(如果適用)
2)下面列出的轉(zhuǎn)換之一(如果它可以產(chǎn)生目標(biāo)類型)
將任何類型的值轉(zhuǎn)換為任何兼容類型始終是不可操作的,并且不會(huì)更改表示形式。
uint8_t (*a)[10]; // if uint8_t is a typedef to unsigned charunsigned char (*b)[] = a; // then these pointer types are compatible
整數(shù)推廣是任意整數(shù)類型的值的隱式轉(zhuǎn)換與秩小于或等于秩為int或類型_Bool,整型,符號(hào)int,unsigned int類型的位域的,以類型的值int
或unsigned int
。
如果int
可以表示原始類型的整個(gè)值范圍(或原始位域的值的范圍),則將該值轉(zhuǎn)換為類型int
。否則,該值將轉(zhuǎn)換為unsigned int
。
整數(shù)升級(jí)保持價(jià)值,包括符號(hào):
int main(void) { void f(); // old-style function declaration char x = 'a'; // integer conversion from int to char f(x); // integer promotion from char back to int}void f(x) int x; {} // the function expects int
上面的 rank 是每個(gè)整數(shù)類型的屬性,定義如下:
1)所有有符號(hào)整數(shù)類型的行列是不同的,并且隨著它們的精度而增加:被簽名的char的等級(jí)<短的等級(jí)<int的等級(jí)<long int的等級(jí)<long long 的等級(jí) int
2)所有有符號(hào)整數(shù)類型的等級(jí)等于對(duì)應(yīng)無符號(hào)整數(shù)類型的等級(jí)
3)任何標(biāo)準(zhǔn)整數(shù)類型的等級(jí)大于任何相同大小的擴(kuò)展整數(shù)類型的等級(jí)(即,__int64 <等級(jí)長long int,但 long long 等級(jí)<由于規(guī)則而等于__int128等級(jí)(1))
4)char 的等級(jí)等于 signed char 的等級(jí)和 unsigned char 的等級(jí)
5)_Bool 的排名小于任何其他標(biāo)準(zhǔn)整數(shù)類型的排名
6)任何枚舉類型的等級(jí)等于其兼容整數(shù)類型的等級(jí)
7)排名是傳遞性的:如果T1的等級(jí)<T2的等級(jí)和T2的等級(jí)<T3的等級(jí),那么T1的等級(jí)<T3的等級(jí)
8)上面未涉及的擴(kuò)展整數(shù)類型的相對(duì)排序的任何方面都是實(shí)現(xiàn)定義的
注意:整數(shù)升級(jí)只適用。
作為通常算術(shù)轉(zhuǎn)換的一部分(見上文)
作為默認(rèn)參數(shù)促銷的一部分(參見上文)
到一元算術(shù)運(yùn)算符的操作數(shù)+和 -
到一元位運(yùn)算符?的操作數(shù)
移位運(yùn)算符<<和>>的兩個(gè)操作數(shù)
任何標(biāo)量類型的值都可以隱式轉(zhuǎn)換為_Bool。將等于零的值轉(zhuǎn)換為0
,將其他所有值轉(zhuǎn)換為1
。
bool b1 = 0.5; // b1 == 1 (0.5 converted to int would be zero)bool b2 = 2.0*_Imaginary_I; // b2 == 1 (but converted to int would be zero)bool b3 = 0.0 + 3.0*I; // b3 == 1 (but converted to int would be zero)bool b4 = 0.0/0.0; // b4 == 1 (NaN does not compare equal to zero)
任何整數(shù)類型的值都可以隱式轉(zhuǎn)換為任何其他整數(shù)類型。除了上述促銷和布爾轉(zhuǎn)換所涵蓋的地方外,規(guī)則如下:
如果目標(biāo)類型可以表示源類型的整個(gè)值范圍,則值不變
否則,如果目標(biāo)類型是無符號(hào)的,則將值2 b(其中b是目標(biāo)類型中的位數(shù))重復(fù)減去或添加到源值直到結(jié)果符合目標(biāo)類型。換句話說,無符號(hào)整數(shù)實(shí)現(xiàn)模運(yùn)算。
否則,如果目標(biāo)類型被簽名,則行為是實(shí)現(xiàn)定義的(可能包括提升信號(hào))
char x = 'a'; // int -> char, result unchangedunsigned char n = -123456; // target is unsigned, result is 192 (that is, -123456+483*256)signed char m = 123456; // target is signed, result is implementation-defined
任何實(shí)數(shù)浮點(diǎn)類型的有限值都可以隱式轉(zhuǎn)換為任何整數(shù)類型。除了上述布爾轉(zhuǎn)換覆蓋的地方,規(guī)則是:
小數(shù)部分被丟棄(截至零)。
如果結(jié)果值可以用目標(biāo)類型表示,則使用該值
否則,行為是不確定的
int n = 3.14; // n == 3int x = 1e10; // undefined behavior for 32-bit int
任何整數(shù)類型的值都可以隱式轉(zhuǎn)換為任何實(shí)數(shù)浮點(diǎn)類型。
如果該值可以完全由目標(biāo)類型表示,則該值不變
如果值可以表示,但不能精確表示,則結(jié)果是最接近的較高值或最接近的較低值(換句話說,舍入方向是實(shí)現(xiàn)定義的),但是如果支持IEEE算術(shù),舍入是最接近的。FE_INEXACT
在這種情況下是否提出是沒有具體說明的。
如果該值不能表示,行為是未定義的,但如果支持IEEE算術(shù),FE_INVALID
則引發(fā)并且結(jié)果值未指定。
這種轉(zhuǎn)換的結(jié)果可能比其目標(biāo)類型指示的范圍和精度更高(請(qǐng)參閱FLT_EVAL_METHOD
。
如果FE_INEXACT
在浮點(diǎn)到整數(shù)轉(zhuǎn)換中需要控制,rint
和nearbyint
可以使用。
double d = 10; // d = 10.00float f = 20000001; // f = 20000000.00 (FE_INEXACT)float x = 1+(long long)FLT_MAX; // undefined behavior
任何實(shí)際浮動(dòng)類型的值都可以隱式轉(zhuǎn)換為任何其他實(shí)際浮動(dòng)類型。
如果該值可以完全由目標(biāo)類型表示,則不會(huì)改變
如果值可以表示,但不能精確表示,則結(jié)果是最接近的較高值或最接近的較低值(換句話說,舍入方向是實(shí)現(xiàn)定義的),但是如果支持IEEE算術(shù),舍入是最接近的
如果該值無法表示,則行為未定義
這種轉(zhuǎn)換的結(jié)果可能比其目標(biāo)類型指示的范圍和精度更高(請(qǐng)參閱FLT_EVAL_METHOD
。
double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625float f = d; // f = 0.100000001490116119384765625float x = 2*(double)FLT_MAX; // undefined
任何復(fù)雜類型的值都可以隱式轉(zhuǎn)換為任何其他復(fù)雜類型。實(shí)部和虛部分別遵循實(shí)際浮動(dòng)類型的轉(zhuǎn)換規(guī)則。
double complex d = 0.1 + 0.1*I;float complex f = d; // f is (0.100000001490116119384765625, 0.100000001490116119384765625)
任何虛構(gòu)類型的值都可以隱式轉(zhuǎn)換為任何其他虛構(gòu)類型。虛部遵循實(shí)際浮動(dòng)類型的轉(zhuǎn)換規(guī)則。
double imaginary d = 0.1*_Imaginary_I;float imaginary f = d; // f is 0.100000001490116119384765625*I
任何實(shí)際浮動(dòng)類型的值都可以隱式轉(zhuǎn)換為任何復(fù)雜類型。
結(jié)果的實(shí)際部分取決于實(shí)際浮動(dòng)類型的轉(zhuǎn)換規(guī)則
結(jié)果的虛部為正零(或非IEEE系統(tǒng)上的無符號(hào)零)
任何復(fù)雜類型的值都可以隱式轉(zhuǎn)換為任何實(shí)際浮動(dòng)類型。
實(shí)部按照真實(shí)浮動(dòng)類型的規(guī)則進(jìn)行轉(zhuǎn)換
虛部被丟棄
注意:在復(fù)數(shù)到實(shí)數(shù)轉(zhuǎn)換中,虛數(shù)部分的 NaN 不會(huì)傳播到實(shí)際結(jié)果。
任何虛數(shù)類型的值都可以隱式轉(zhuǎn)換為任何實(shí)數(shù)類型(整型或浮點(diǎn)型)。除目標(biāo)類型為_Bool 之外,結(jié)果始終為正值(或無符號(hào))零,在這種情況下,布爾轉(zhuǎn)換規(guī)則適用。
任何實(shí)數(shù)類型的值都可以隱式轉(zhuǎn)換為任何虛數(shù)類型。結(jié)果總是一個(gè)正的虛構(gòu)的零。
任何虛構(gòu)類型的值都可以隱式轉(zhuǎn)換為任何復(fù)雜類型。
結(jié)果的實(shí)際部分是正的零
結(jié)果的虛數(shù)部分遵循相應(yīng)實(shí)際類型的轉(zhuǎn)換規(guī)則
任何復(fù)雜類型的值都可以隱式轉(zhuǎn)換為任何虛構(gòu)類型。
真正的部分被丟棄
結(jié)果的虛數(shù)部分遵循相應(yīng)實(shí)際類型的轉(zhuǎn)換規(guī)則
double imaginary z = I * (3*I); // the complex result -3.0+0i loses real part, gives zero
一個(gè)指針void
可以使用以下語義隱式轉(zhuǎn)換為指向?qū)ο箢愋偷闹羔槪?/p>
如果指向?qū)ο蟮闹羔樲D(zhuǎn)換為指向 void 和指向的指針,則其值將與原始指針相等。
沒有其他擔(dān)保提供
int* p = malloc(10 * sizeof(int)); // malloc returns void*
指向非限定類型的指針可以隱式轉(zhuǎn)換為指向該類型限定版本的指針(換句話說,可以添加 const,volatile和 restrict 限定符。原始指針和結(jié)果比較相等。
int n;const int* p = &n; // &n has type int*
任何具有值的整數(shù)常量表達(dá)式0
以及將值void*
轉(zhuǎn)換為0的整型指針表達(dá)式都可以隱式轉(zhuǎn)換為任何指針類型(既指向?qū)ο笥种赶蚝瘮?shù)的指針)。結(jié)果是它的類型的空指針值,保證比較不等于該類型的任何非空指針值。這個(gè)整數(shù)或 void *表達(dá)式被稱為空指針常量,標(biāo)準(zhǔn)庫提供這個(gè)常量的一個(gè)定義作為宏NULL
。
int* p = 0;double* q = NULL;
盡管任何算術(shù)運(yùn)算符中的有符號(hào)整數(shù)溢出都是未定義行為,但在整數(shù)轉(zhuǎn)換中溢出有符號(hào)整數(shù)類型僅僅是未指定的行為。
另一方面,盡管任何算術(shù)運(yùn)算符(和整數(shù)轉(zhuǎn)換)中的無符號(hào)整數(shù)溢出是一個(gè)定義明確的操作,并遵循模算術(shù)規(guī)則,但浮點(diǎn)到整數(shù)轉(zhuǎn)換中的無符號(hào)整數(shù)溢出是未定義的行為:可以轉(zhuǎn)換為無符號(hào)整數(shù)的實(shí)際浮動(dòng)類型的值是來自打開間隔(-1; Unnn_MAX + 1)的值。
unsigned int n = -1.0; // undefined behavior
指針和整數(shù)之間的轉(zhuǎn)換(除了指向_Bool 的指針和整數(shù)常量表達(dá)式,值為零到指針)之間,指向?qū)ο蟮闹羔槪ǔ侵赶?void 的指針或指向 void 的指針之外)以及指向函數(shù)的指針之間的轉(zhuǎn)換函數(shù)具有兼容類型)從不隱含,并且需要一個(gè)演員操作符。
在指向函數(shù)的指針和指向?qū)ο蟮闹羔槪ò?void *)或整數(shù)之間沒有轉(zhuǎn)換(隱式或顯式)。
C11 standard (ISO/IEC 9899:2011):
6.3 Conversions (p: 50-56)
C99 standard (ISO/IEC 9899:1999):
6.3 Conversions (p: 42-48)
C89/C90 standard (ISO/IEC 9899:1990):
3.2 Conversions