簡體   English   中英

關於常用算術轉換的問題 - GCC編譯器

[英]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

這就是我期望發生的事情:

  1. Typecast優先,LHS -變為signed int

  2. -操作。 此處不會發生整數提升或隱式轉換,因為LHS和RHS已經都是signed int 操作的結果是-1,數據類型為signed int

  3. printf語句中,值-1保留在轉換為long long int ,並顯示-1作為結果。

有人可以解釋我邏輯中的缺陷在哪里嗎?

由於%lldint類型的不適當的格式說明符,因此它是未定義的行為

是的(signed int)a - 1是一個值為-1int類型,但是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM