簡體   English   中英

無符號按位移位運算符[C11]

[英]Unsigned Bitwise Shift Operators [C11]

編輯:如下所示,我錯過了ANSI C標准的第一部分:“ 如果右操作數的值為負或大於或等於提升的左操作數的寬度,則行為未定義。 ”錯誤(或者缺少錯誤/錯誤的不同)是由於我使用的是特定的編譯器。

我遇到了一些奇怪的事情,希望有人可以闡明我在這里的無知。 必要的示例代碼如下:

#include <stdio.h>
int main(void)
{
    unsigned a, b;
    int w, x, y;

    a = 0x00000001;
    b = 0x00000020;
    w = 31;
    x = 32;
    y = 33;

    a << w; /*No error*/
    a << x; /*No error*/
    a << y; /*No error*/

    a << 31; /*No error*/
    a << 32; /*Error*/
    a << 33; /*Error*/

    a << 31U; /*No error*/
    a << 32U; /*Error*/
    a << 33U; /*Error*/

    a << w + 1; /*No error*/
    a << b; /*No error*/

    return 0;
}

我的問題是:為什么為原始數字返回錯誤,而不為任何變量返回錯誤? 我認為,應該對它們進行同樣的對待。 根據C11標准

E1 << E2的結果是E1左移E2位位置; 空位用零填充。 如果E1具有無符號類型,則結果的值為E1×2 ^ E2,比結果類型中可表示的最大值多模減少1。 如果E1具有帶符號的類型和非負值,並且E1×2 E2在結果類型中可表示,則這是結果值; 否則,行為是不確定的。

右邊,因為左邊是無符號類型,應該比結果類型中可表示的最大值大2模比E2減少。...這句話對我來說並不完全清楚,但實際上似乎是E1 <<(E2%32)-盡管32不是結果類型中可表示的最大值。 無論如何,對於C11標准不是未定義的,但是錯誤

左移計數> =類型的寬度[默認啟用]

嘗試編譯時顯示。 我無法推斷出為什么> 31的某些值起作用(例如x = 33; a <

我在64位Fedora上使用GCC編譯器。 提前致謝。 -將

我的問題是:為什么為原始數字返回錯誤,而不為任何變量返回錯誤?

因為缺少編譯器警告並不能保證良好的程序行為。 編譯器對a << x發出警告是正確的,但並非必須如此。

我認為應該對他們進行同樣的對待

編譯器在警告a << 33時對您有所幫助。 當它不為a << y發出警告時,它不會幫您任何忙,但是編譯器不必幫您任何忙。

如果要確定程序不包含未定義的行為,則可以不依賴於缺少編譯器警告,但是可以使用聲音靜態分析器。 如果用於不確定行為的聲音靜態分析儀未在您的程序中檢測到任何東西,那么您可以得出結論,它不會產生任何聲音(對要使用的分析儀記錄使用條件的模數)。 例如:

$ frama-c -val tc ... tc:13:[kernel] warning: invalid RHS operand for shift. assert 0 ≤ x < 32;

實際上,這似乎是E1 <<(E2%32)

您看到的原因是,這是x86_64指令集中的shift指令實現的行為。 但是, 將負號或大於類型寬度的數字移位是未定義的行為 它在其他體系結構上的工作方式有所不同,甚至您體系結構的某些編譯器也可能在編譯時(作為恆定傳播階段的一部分)使用與您注意到的規則不同的規則對其進行計算。 不要再依賴於E1 << (E2%32)的結果,而不再依賴於free() d之后仍然包含正確結果的內存。

右邊,因為左邊是無符號類型,應該比結果類型中可表示的最大值大2模比E2減少。...這句話對我來說並不完全清楚,但實際上似乎是E1 <<(E2%32)-盡管32不是結果類型中可表示的最大值。

那不是正確的解釋。 結果是模2 ^ 32,而不是E2。 那句話描述的是如何丟棄從左側移出的位。 結果,如果允許的話,任何大於或等於int位數的E2都將為零。 由於移位大於或等於該位數是未定義的行為,因此編譯器幫助您在編譯時生成錯誤,而不是將其保留到運行時才發生奇怪和不正確的事情。

對於n位,僅當值x> 0x <= n-1時才可以進行數據移位,其中x是無位移位。

在這種情況下,無符號的內存大小等於32位,因此僅可能的移位范圍是1到31。您正在嘗試將數據移位到超出該變量的存儲大小的位置,這就是為什么會給您帶來錯誤。

比結果類型中可表示的最大值多一個模。...

表示E1 * 2^E2的值對unsigned int mod (UINT_MAX+1)降為mod (UINT_MAX+1) 這與您關於E2的假設完全無關。

無論如何,對於C11標准,它不是未定義的,

您忘記閱讀引用的段落之前的內容:

如果右操作數的值為負或大於或等於提升的左操作數的寬度,則行為是不確定的。

所有32或更多的移位都會導致不確定的行為。 不需要編譯器對此發出警告,但是在某些情況下,這對您很高興。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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