[英]Question on Usual Arithmetic Conversions - GCC Compiler
我正在嘗試理解C中的隱式數據類型轉換。我認為我已經理解了這個主題,但是下面的代碼示例仍然讓我感到困惑。
具體來說,我之前已經從C標准草案中讀到了關於通常的算術轉換和整數提升。
unsigned short int a = 0;
printf("\n%lld", (signed int)a - 1);
我正在使用GCC進行編譯。
unsigned short int
是2個字節。 int
是4個字節。
當我運行此代碼時,我得到以下結果: 4294967295
我期待結果-1 。
這就是我期望發生的事情:
Typecast優先,LHS -
變為signed int
。
-
操作。 此處不會發生整數提升或隱式轉換,因為LHS和RHS已經都是signed int
。 操作的結果是-1,數據類型為signed int
。
在printf
語句中,值-1保留在轉換為long long int
,並顯示-1作為結果。
有人可以解釋我邏輯中的缺陷在哪里嗎?
由於%lld
是int
類型的不適當的格式說明符,因此它是未定義的行為 。
是的(signed int)a - 1
是一個值為-1
的int
類型,但是printf
調用是未定義的部分。 C標准中沒有任何內容表明轉換為long long
會發生。
在printf語句中,值-1保留在long long int的轉換中
沒有發生這樣的轉換。 printf
(函數族)是啞的,需要一個與參數列表類型相對應的格式字符串。
printf
不工作像一個普通的函數void f (long long int x)
這將迫使的隱式轉換的參數(“按分配” /“左值轉換”)的類型。 這會給你預期的“符號擴展”。
值得注意的是,這里還有另一種專門的隱式轉換,稱為默認參數提升 ,僅適用於沒有原型的變量參數函數和函數。
C17 6.5.2.2/6
如果表示被調用函數的表達式具有不包含原型的類型,則對每個參數執行整數提升,並將具有
float
類型的參數提升為double
。 這些被稱為默認參數促銷 。
關於變量參數函數的C17 6.5.2.2/7:
函數原型聲明符中的省略號表示法導致參數類型轉換在最后聲明的參數之后停止。 默認參數提升是在尾隨參數上執行的。
在實踐中,這意味着:
printf
float
在函數調用期間被隱式轉換為double
。 printf
小整數類型在函數調用期間根據整數提升進行隱式轉換,最有可能以int
結尾。 printf
其他類型在函數調用期間不會被隱式提升。 然后傳遞和可能轉換的參數在內部處理,就好像它是轉換說明符指定的類型一樣。 如果那個與實際類型不匹配,則代碼具有未定義的行為。
在你的情況下你傳遞一個int
,它不會被隱式提升,但是當printf
將它視為long long
,你會得到未定義的行為。
在這里你可以認為自己很幸運。 a
是一個short int
,經常進行“signed int”的算術轉換,即使是演員也是如此
unsigned short int a = 0;
printf("\n%d", (signed int)a - 1);
和
unsigned short int a = 0;
printf("\n%d", a - 1);
如果 unsigned short
所有值都可以在int
中表示(就像在你的情況下那樣), 則會有相同的行為。 轉換的結果是int
。 現在,對於變量參數,將應用默認參數升級,並且任何小於int
將轉換為int
如果可表示,否則為unsigned int
。 但是lld
期望一個有signed long long int
,它是8字節寬。 默認參數提升不提倡int
隱式long long int
。
幸運部分來了 - 你確實得到了錯誤的價值。 請注意,由於行為未定義,您可以獲得您期望的值, 這次 - 畢竟它在64位處理器上是完全可行的!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.