簡體   English   中英

為什么用 0xff 對字符進行按位與?

[英]Why do a bitwise-and of a character with 0xff?

我正在閱讀一些實現簡單解析器的代碼。 名為scan的 function 將一行分解為標記。 scan有一個 static 變量bp ,它分配了要標記的行。 在賦值之后,空白被跳過。 見下文。 我不明白的是為什么代碼會按位和bp指向的字符0xff ,即* bp & 0xff的目的是什么? 這怎么樣:

while (isspace(* bp & 0xff))
    ++ bp;

與此不同:

while (isspace(* bp))
    ++ bp;

這是scan function:

static enum tokens scan (const char * buf)
                    /* return token = next input symbol */
{   static const char * bp;

    while (isspace(* bp & 0xff))
        ++ bp;

        ..
}

來自 C 標准(7.4 字符處理 <ctype.h>)

1 header <ctype.h> 聲明了幾個對字符分類和映射有用的函數。198)在所有情況下,參數都是一個 int,其值應表示為無符號字符或應等於宏 EOF 的值。 如果參數有任何其他值,則行為未定義。

在這次通話中

isspace(* bp)

由於 integer 促銷活動,具有char類型的參數表達式*bp被轉換為int類型。

如果char類型表現為signed char類型並且表達式*bp的值為負,則提升的int類型的表達式的值也將為負並且不能表示為unsigned char類型的值。

這會導致未定義的行為。

在這次通話中

isspace(* bp & 0xff)

由於按位運算符 & 類型的表達式* bp & 0xff的結果值可以表示為int unsigned char類型的值。

所以這是一個技巧,而不是編寫更清晰的代碼

isspace( ( unsigned char )*bp )

function isspace通常是這樣實現的,它使用int類型的參數作為具有 256 個值(從 0 到 255)的表中的索引。 如果int類型的參數的值大於最大值 255 或負值(並且不等於宏 EOF 的值),則 function 的行為未定義。

cppreference isspace()The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF

*bp為負數時,例如它是-42 ,那么它不能表示為unsigned char ,因為它是負數並且unsigned char必須是正數或零。

在二進制補碼系統上,值被符號擴展為更大的“寬度”,因此它們將設置最左邊的位。 然后,當您采用更寬類型的0xff時,最左邊的位被清除,最終得到一個正值,小於或等於0xff ,我的意思是可以表示為unsigned char

注意 arguments 到&經歷隱式提升,所以*bp的結果在調用isspace之前被轉換為int 讓我們假設*bp = -42例如並假設一個健全的平台,帶有 8 位 char 已簽名並且int具有 32 位,然后:

*bp & 0xff               # expand *bp = -42
(char)-42 & 0xff         # apply promotion
(int)-42 & 0xff          # lets convert to hex assuming twos-complement
(int)0xffffffd6 & 0xff   # do & operation
(int)0xd6                # lets convert to decimal
214                      # representable as unsigned char, all fine

如果沒有& 0xff ,負值將導致未定義的行為。

我建議更喜歡isspace((unsigned char)*bp)

基本上最簡單的isspace實現看起來就像

static const char bigarray[257] = { 0,0,0,0,0,...1,0,1,0,... };
// note: EOF is -1
#define isspace(x)  (bigarray[(x) + 1])

在這種情況下你不能通過例如-42 ,因為bigarray[-41]是無效的。

你的問題:

這怎么樣:

while (isspace(* bp & 0xff))
    ++ bp;

與此不同:

while (isspace(* bp))
    ++ bp;

不同之處在於,在第一個示例中,您始終將bp處的最低字節傳遞給isspace ,這是由於按位與完整位掩碼( 0b111111110xff )的結果。 isspace的參數可能包含大於 1 個字節的類型。 例如, isspace被定義為isspace(int c) ,所以你可以看到這里的參數是一個int ,它可能是多個字節,具體取決於你的系統。

簡而言之,這是一個健全性檢查,以確保isspace僅比較bp變量中的單個字節。

while (isspace(* bp & 0xff))
    ++ bp;

&&

while (isspace(* bp))
    ++ bp;

嚴格來說,如果bp不引用unsigned char ,兩者都是不正確的。

在這種情況下,它應該是:

while (isspace((unsigned char)(*bp & 0xff)))
    ++ bp;

或更好

while (isspace(*bp == EOF ? EOF : (unsigned char)(*bp & 0xff)))
    ++ bp; 

如果參數不是EOF或它沒有unsigned char的值,則 isspace 未定義

如果*bp引用char它必須是:

while (isspace((unsigned char)(*bp)))
    ++bp;

在 c 中,char 可以有符號或無符號https://en.wikipedia.org/wiki/C_data_types

當傳遞給isspace時, bp將被提升為 integer。 如果它是有符號的並且設置了高位,那么它將被符號擴展為負 integer。 這可能意味着它不是isspace function https://linux.die.net/man/3/isspaceNo

請參閱http://cpp.sh/9mp2i了解它如何更改按位並更改 isspace 的值

如果我們假設 char 類型的位總是 8,
那么這里帶有 0xff 的代碼按位與運算符會讓我們感到困惑。

但是,如果 char 類型並不總是 8 位,那又如何呢?
那么0xff可能還有別的意思吧?

實際上, char 類型並不總是 8 位,我們可以在 C99 標准中看到詳細信息。 標准中的 char 類型未定義為 8 位。

以下是 C99 標准如何描述 char 類型的大小。

6.5.3.4 sizeof 運算符 當應用於具有charunsigned charsigned char類型(或其限定版本)的操作數時,結果為 1 當應用於具有數組類型的操作數時,結果是數組中的總字節數。)當應用於具有結構或聯合類型的操作數時,結果是此類 object 中的總字節數,包括內部和尾隨填充。

6.2.5 類型聲明為 char 類型的 object 大到足以存儲基本執行字符集的任何成員 如果基本執行字符集的成員存儲在 char object 中,則其值保證為正。 如果任何其他字符存儲在 char object 中,則結果值是實現定義的,但應在該類型可以表示的值范圍內。

例如,德州儀器公司的 TMS320C28x DSP 有一個 16 位的字符。
對於編譯器在此處指定, CHAR_BIT 為 16 (第 99 頁)。

這似乎是一個現代處理器(目前正在出售),編譯器支持 C99 和 C++03。

暫無
暫無

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

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