?
Dieses Dokument verwendet PHP-Handbuch für chinesische Websites Freigeben
當預(yù)期在不同類型的值的上下文中使用表達式時,可能會發(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ā)生在以下情況:
在賦值運算符中,右側(cè)操作數(shù)的值被轉(zhuǎn)換為左側(cè)操作數(shù)的非限定類型。
在標量初始化中,初始化表達式的值被轉(zhuǎn)換為被初始化的對象的非限定類型
在函數(shù)調(diào)用表達式中,對于具有原型的函數(shù),將每個參數(shù)表達式的值轉(zhuǎn)換為相應(yīng)參數(shù)的非限定聲明類型
在return語句中,操作數(shù)的值return
被轉(zhuǎn)換為具有函數(shù)返回類型的對象
請注意,除轉(zhuǎn)換外,實際分配也會從浮點類型中移除額外的范圍和精度,并禁止重疊; 這些特性不適用于轉(zhuǎn)換,就像通過分配一樣。
在調(diào)用時的函數(shù)調(diào)用表達式中。
1)沒有原型的功能
2)可變參數(shù)函數(shù),其中參數(shù)表達式是與省略號參數(shù)匹配的尾隨參數(shù)之一
整數(shù)類型的每個參數(shù)都經(jīng)過整數(shù)提升(參見下文),并且每個類型的參數(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)
請注意,float
complex
和float
imaginary
沒有提升到double
complex
和double
imaginary
在這種情況下。
以下算術(shù)運算符的參數(shù)經(jīng)過隱式轉(zhuǎn)換,以獲得公共實數(shù)類型,這是執(zhí)行計算的類型:
二進制算術(shù)*,/,%,+, -
關(guān)系運算符<,>,<=,> =,==,!=
二進制按位運算&,^,|,
條件操作符?:
1)如果一個操作數(shù)是long double
,long
double
complex
或long
double
imaginary
,另一個操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)或?qū)嶋H浮動類型 long double
復雜類型 long
double
complex
虛構(gòu)類型 long
double
imaginary
2)否則,如果一個操作數(shù)是double
,double
complex
或double
imaginary
,另一個操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)或?qū)嶋H浮動類型 double
復雜類型 double
complex
虛構(gòu)類型 double
imaginary
3)否則,如果一個操作數(shù)是float
,float
complex
或float
imaginary
,另一個操作數(shù)被隱式轉(zhuǎn)換如下:
整數(shù)類型為float
(唯一可能的實際類型是float,保持原樣)
復雜類型依然存在 float
complex
虛構(gòu)類型仍然存在 float
imaginary
4)否則,兩個操作數(shù)都是整數(shù)。在這種情況下,首先,兩個操作數(shù)都進行整數(shù)升級(見下文)。然后
如果促銷后的類型相同,則該類型是常見類型
否則,如果促銷后的兩個操作數(shù)具有相同的簽名(均為有符號或無符號),則具有較低轉(zhuǎn)換等級的操作數(shù)(請參見下文)會隱式轉(zhuǎn)換為具有較高轉(zhuǎn)換等級的操作數(shù)的類型
否則,簽名會有所不同:如果具有無符號類型的操作數(shù)的轉(zhuǎn)換等級大于或等于有符號操作數(shù)類型的等級,則帶符號類型的操作數(shù)將隱式轉(zhuǎn)換為無符號類型
否則,簽名是不同的,并且?guī)Х柕牟僮鲾?shù)的等級大于無符號的操作數(shù)的等級。在這種情況下,如果有符號類型可以表示所有無符號類型的值,那么具有無符號類型的操作數(shù)將隱式轉(zhuǎn)換為有符號操作數(shù)的類型。
否則,兩個操作數(shù)都會隱式轉(zhuǎn)換為帶符號操作數(shù)類型的無符號類型。
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é)果類型確定如下:
如果兩個操作數(shù)都很復雜,則結(jié)果類型很復雜
如果兩個操作數(shù)都是虛構(gòu)的,則結(jié)果類型是虛構(gòu)的
如果兩個操作數(shù)都是實數(shù),則結(jié)果類型是實數(shù)
如果兩個浮點操作數(shù)具有不同的類型域(復數(shù)與實數(shù),復數(shù)與虛數(shù),或虛數(shù)與實數(shù)),則結(jié)果類型很復雜
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
與往常一樣,浮點運算符的結(jié)果可能比其類型所指示的范圍和精度更高(請參閱參考資料FLT_EVAL_METHOD
)。
注意:實數(shù)和虛數(shù)操作數(shù)不會隱式轉(zhuǎn)換為復數(shù),因為這樣做需要額外的計算,而在涉及無窮大,NaN和帶符號的零的某些情況下會產(chǎn)生不希望的結(jié)果。例如,如果將實數(shù)轉(zhuǎn)換為復數(shù),則2.0×(3.0 +i∞)將評估為(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)換為復數(shù),則i2.0×(∞+ i3.0)將評估為(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ī)則,計算總是可以以窄于指定符的類型執(zhí)行。
任何非數(shù)組類型的任何左值表達式,當在除。以外的任何上下文中使用時。
作為操作符的操作數(shù)(如果允許)
作為前/后增量和減量運算符的操作數(shù)。
作為成員訪問(點)運算符的左側(cè)操作數(shù)。
作為賦值和復合賦值操作符的左側(cè)操作數(shù)。
作為 sizeof 的操作數(shù)
進行左值轉(zhuǎn)換:類型保持不變,但會丟失 const / volatile / restrict-qualifiers 和原子屬性(如果有的話)。價值保持不變,但失去了左值屬性(地址可能不再被采用)。
如果左值具有不完整類型,則行為未定義。
如果左值指定一個自動存儲持續(xù)時間的對象,其地址從未被采用,并且該對象未初始化(未使用初始化器聲明并且在使用之前未對其進行分配),則行為是未定義的。
此轉(zhuǎn)換將模擬對象的值從其位置的內(nèi)存負載。
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ù)組類型的任何左值表達式,當在除。以外的任何上下文中使用時。
作為操作符地址的操作數(shù)
作為 sizeof 的操作數(shù)
作為用于數(shù)組初始化的字符串文字
經(jīng)歷轉(zhuǎn)換到非左值指針到它的第一個元素。
如果數(shù)組被聲明為注冊,則行為是未定義的。
int a[3], b[3][4];int* p = a; // conversion to &a[0]int (*q)[4] = b; // conversion to &b[0]
任何函數(shù)指示符表達式,當在除。以外的任何上下文中使用時。
作為操作符地址的操作數(shù)
作為sizeof的操作數(shù)
經(jīng)過轉(zhuǎn)換到非左值指針指向由表達式指定的函數(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)換,都由兩個階段組成:
1)價值轉(zhuǎn)化(如果適用)
2)下面列出的轉(zhuǎn)換之一(如果它可以產(chǎn)生目標類型)
將任何類型的值轉(zhuǎn)換為任何兼容類型始終是不可操作的,并且不會更改表示形式。
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,整型,符號int,unsigned int類型的位域的,以類型的值int
或unsigned int
。
如果int
可以表示原始類型的整個值范圍(或原始位域的值的范圍),則將該值轉(zhuǎn)換為類型int
。否則,該值將轉(zhuǎn)換為unsigned int
。
整數(shù)升級保持價值,包括符號:
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 是每個整數(shù)類型的屬性,定義如下:
1)所有有符號整數(shù)類型的行列是不同的,并且隨著它們的精度而增加:被簽名的char的等級<短的等級<int的等級<long int的等級<long long 的等級 int
2)所有有符號整數(shù)類型的等級等于對應(yīng)無符號整數(shù)類型的等級
3)任何標準整數(shù)類型的等級大于任何相同大小的擴展整數(shù)類型的等級(即,__int64 <等級長long int,但 long long 等級<由于規(guī)則而等于__int128等級(1))
4)char 的等級等于 signed char 的等級和 unsigned char 的等級
5)_Bool 的排名小于任何其他標準整數(shù)類型的排名
6)任何枚舉類型的等級等于其兼容整數(shù)類型的等級
7)排名是傳遞性的:如果T1的等級<T2的等級和T2的等級<T3的等級,那么T1的等級<T3的等級
8)上面未涉及的擴展整數(shù)類型的相對排序的任何方面都是實現(xiàn)定義的
注意:整數(shù)升級只適用。
作為通常算術(shù)轉(zhuǎn)換的一部分(見上文)
作為默認參數(shù)促銷的一部分(參見上文)
到一元算術(shù)運算符的操作數(shù)+和 -
到一元位運算符?的操作數(shù)
移位運算符<<和>>的兩個操作數(shù)
任何標量類型的值都可以隱式轉(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ī)則如下:
如果目標類型可以表示源類型的整個值范圍,則值不變
否則,如果目標類型是無符號的,則將值2 b(其中b是目標類型中的位數(shù))重復減去或添加到源值直到結(jié)果符合目標類型。換句話說,無符號整數(shù)實現(xiàn)模運算。
否則,如果目標類型被簽名,則行為是實現(xiàn)定義的(可能包括提升信號)
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ù)浮點類型的有限值都可以隱式轉(zhuǎn)換為任何整數(shù)類型。除了上述布爾轉(zhuǎn)換覆蓋的地方,規(guī)則是:
小數(shù)部分被丟棄(截至零)。
如果結(jié)果值可以用目標類型表示,則使用該值
否則,行為是不確定的
int n = 3.14; // n == 3int x = 1e10; // undefined behavior for 32-bit int
任何整數(shù)類型的值都可以隱式轉(zhuǎn)換為任何實數(shù)浮點類型。
如果該值可以完全由目標類型表示,則該值不變
如果值可以表示,但不能精確表示,則結(jié)果是最接近的較高值或最接近的較低值(換句話說,舍入方向是實現(xiàn)定義的),但是如果支持IEEE算術(shù),舍入是最接近的。FE_INEXACT
在這種情況下是否提出是沒有具體說明的。
如果該值不能表示,行為是未定義的,但如果支持IEEE算術(shù),FE_INVALID
則引發(fā)并且結(jié)果值未指定。
這種轉(zhuǎn)換的結(jié)果可能比其目標類型指示的范圍和精度更高(請參閱FLT_EVAL_METHOD
。
如果FE_INEXACT
在浮點到整數(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
任何實際浮動類型的值都可以隱式轉(zhuǎn)換為任何其他實際浮動類型。
如果該值可以完全由目標類型表示,則不會改變
如果值可以表示,但不能精確表示,則結(jié)果是最接近的較高值或最接近的較低值(換句話說,舍入方向是實現(xiàn)定義的),但是如果支持IEEE算術(shù),舍入是最接近的
如果該值無法表示,則行為未定義
這種轉(zhuǎn)換的結(jié)果可能比其目標類型指示的范圍和精度更高(請參閱FLT_EVAL_METHOD
。
double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625float f = d; // f = 0.100000001490116119384765625float x = 2*(double)FLT_MAX; // undefined
任何復雜類型的值都可以隱式轉(zhuǎn)換為任何其他復雜類型。實部和虛部分別遵循實際浮動類型的轉(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)類型。虛部遵循實際浮動類型的轉(zhuǎn)換規(guī)則。
double imaginary d = 0.1*_Imaginary_I;float imaginary f = d; // f is 0.100000001490116119384765625*I
任何實際浮動類型的值都可以隱式轉(zhuǎn)換為任何復雜類型。
結(jié)果的實際部分取決于實際浮動類型的轉(zhuǎn)換規(guī)則
結(jié)果的虛部為正零(或非IEEE系統(tǒng)上的無符號零)
任何復雜類型的值都可以隱式轉(zhuǎn)換為任何實際浮動類型。
實部按照真實浮動類型的規(guī)則進行轉(zhuǎn)換
虛部被丟棄
注意:在復數(shù)到實數(shù)轉(zhuǎn)換中,虛數(shù)部分的 NaN 不會傳播到實際結(jié)果。
任何虛數(shù)類型的值都可以隱式轉(zhuǎn)換為任何實數(shù)類型(整型或浮點型)。除目標類型為_Bool 之外,結(jié)果始終為正值(或無符號)零,在這種情況下,布爾轉(zhuǎn)換規(guī)則適用。
任何實數(shù)類型的值都可以隱式轉(zhuǎn)換為任何虛數(shù)類型。結(jié)果總是一個正的虛構(gòu)的零。
任何虛構(gòu)類型的值都可以隱式轉(zhuǎn)換為任何復雜類型。
結(jié)果的實際部分是正的零
結(jié)果的虛數(shù)部分遵循相應(yīng)實際類型的轉(zhuǎn)換規(guī)則
任何復雜類型的值都可以隱式轉(zhuǎn)換為任何虛構(gòu)類型。
真正的部分被丟棄
結(jié)果的虛數(shù)部分遵循相應(yīng)實際類型的轉(zhuǎn)換規(guī)則
double imaginary z = I * (3*I); // the complex result -3.0+0i loses real part, gives zero
一個指針void
可以使用以下語義隱式轉(zhuǎn)換為指向?qū)ο箢愋偷闹羔槪?/p>
如果指向?qū)ο蟮闹羔樲D(zhuǎn)換為指向 void 和指向的指針,則其值將與原始指針相等。
沒有其他擔保提供
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ù)常量表達式0
以及將值void*
轉(zhuǎn)換為0的整型指針表達式都可以隱式轉(zhuǎn)換為任何指針類型(既指向?qū)ο笥种赶蚝瘮?shù)的指針)。結(jié)果是它的類型的空指針值,保證比較不等于該類型的任何非空指針值。這個整數(shù)或 void *表達式被稱為空指針常量,標準庫提供這個常量的一個定義作為宏NULL
。
int* p = 0;double* q = NULL;
盡管任何算術(shù)運算符中的有符號整數(shù)溢出都是未定義行為,但在整數(shù)轉(zhuǎn)換中溢出有符號整數(shù)類型僅僅是未指定的行為。
另一方面,盡管任何算術(shù)運算符(和整數(shù)轉(zhuǎn)換)中的無符號整數(shù)溢出是一個定義明確的操作,并遵循模算術(shù)規(guī)則,但浮點到整數(shù)轉(zhuǎn)換中的無符號整數(shù)溢出是未定義的行為:可以轉(zhuǎn)換為無符號整數(shù)的實際浮動類型的值是來自打開間隔(-1; Unnn_MAX + 1)的值。
unsigned int n = -1.0; // undefined behavior
指針和整數(shù)之間的轉(zhuǎn)換(除了指向_Bool 的指針和整數(shù)常量表達式,值為零到指針)之間,指向?qū)ο蟮闹羔槪ǔ侵赶?void 的指針或指向 void 的指針之外)以及指向函數(shù)的指針之間的轉(zhuǎn)換函數(shù)具有兼容類型)從不隱含,并且需要一個演員操作符。
在指向函數(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