[英]Safe low 32 bits masking of uint64_t
假設以下代碼:
uint64_t g_global_var;
....
....
void foo(void)
{
uint64_t local_32bit_low = g_global_var & 0xFFFFFFFF;
....
}
在當前的工具鏈,這個代碼正常工作, local_32bit_low
確實含有的低32位g_global_var
。
我想知道標准C是否保證此代碼始終按預期工作? 我擔心的是編譯器可能將0xFFFFFFFF視為-1的整數值,當提升到uint64_t
,它將變為0xFFFFFFFFFFFFFFFF。
PS
我知道為了安全起見,在這種情況下最好使用0xFFFFFFFFULL。 關鍵是我在遺留代碼中看到它,我想知道它是否值得修復。
沒有問題。 整數常量0xFFFFFFFF
具有能夠按原樣存儲值的類型。
根據C標准(6.4.4.1整數常數)
5整數常量的類型是相應列表中可以表示其值的第一個
因此,此值存儲為正值。
如果unsigned int
類型是32位整數類型,則常量將具有unsigned int
類型。
否則它將具有可以存儲值的類型之一。
long int
unsigned long int
long long int
unsigned long long int
由於表達式中通常的算術轉換
g_global_var & 0xFFFFFFFF;
它被提升為
0x00000000FFFFFFFF
注意在C中沒有負整數常量。 例如,表達式
-10
由兩個子表達式組成:主表達式10
和帶有一元運算符的子表達式-
-19
與完整表達式一致。
0xffffffff不是-1,永遠。 如果你強制轉換(或通過賦值)它可以轉換為-1,它可以轉換為有符號的32位類型,但C中的整數文字總是有它們的數學值,除非它們溢出。
對於十進制文字,類型是可以表示值的最窄簽名類型。 對於十六進制文字,在進入下一個更寬的簽名類型之前使用無符號類型。 因此,在int
為32位的常見情況下,0xffffffff將具有unsigned int
類型。 如果你把它寫成十進制,它將有long
類型(如果long
是64位)或long long
(如果long
只有32位)。
未填充的十六進制或八進制常量的類型是以下列表中的第一個,其值可以表示為:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
(對於未加十進制的十進制常量,請從上面的列表中刪除unsigned
類型。)
十六進制常量0xFFFFFFFF
絕對可以用unsigned long int
表示,因此它的類型將是int
, unsigned int
, long int
或unsigned long int
,可以表示其值。
請注意,雖然0xFFFFFFFF > 0
總是計算為1(真),但在不同的實現上, 0xFFFFFFFF > -1
可能會計算為0(假)或1(真)。 因此,在將整數常量相互比較或與整數類型的其他對象進行比較時需要注意。
其他人已經回答了這個問題,只是一個推薦,下次(如果你在C11下)你可以自己使用_Generic
檢查表達式的類型
#include <stdio.h>
#include <stdint.h>
#define print_type(x) _Generic((x), \
int64_t: puts("int64_t"), \
uint64_t: puts("uint64_t"), \
default: puts("unknown") \
)
uint64_t g_global_var;
int main(void)
{
print_type(g_global_var & 0xFFFFFFFF);
return 0;
}
輸出是
uint64_t
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.