簡體   English   中英

gcc 7.2:警告:左移計數> =類型的寬度

[英]gcc 7.2: warning: left shift count >= width of type

即使我將每個正確的操作數都強制轉換為unsigned long long ,警告仍然存在。 uint8_t << uint64_t是否應該具有這樣的隱式轉換: (uint64_t) uint8_t << uint64_t

這個答案表明我可以提升兩個操作數中的任何一個,整個表達式都將轉換為unsigned long long ,但這可能是錯誤的。

bool dgBioReadU64LE(DgBioFile *file, uint64_t *x) {
    uint8_t u[8];
    if (!dgBioReadU8v(file, LEN(u), u)) return false;
    *x = u[0]|(u[1]<<8ULL)|(u[2]<<16ULL)|(u[3]<<24ULL)|(u[4]<<32ULL)|(u[5]<<40ULL)|(u[6]<<48ULL)|(u[7]<<56ULL);
    return true;
}

bool dgBioReadU64BE(DgBioFile *file, uint64_t *x) {
    uint8_t u[8];
    if (!dgBioReadU8v(file, LEN(u), u)) return false;
    *x = u[7]|(u[6]<<8ULL)|(u[5]<<16ULL)|(u[4]<<24ULL)|(u[3]<<32ULL)|(u[2]<<40ULL)|(u[1]<<48ULL)|(u[0]<<56ULL);
    return true;
}

uint8_t << uint64_t是否應該具有這樣的隱式轉換: (uint64_t) uint8_t << uint64_t

TL; DR-不,移位運算符很特殊。

完整答案

您描述的行為(本質上是匹配的操作數類型)在C標准中稱為通常的算術轉換 1個

我們看到該標准對許多運營商(例如,加性運營商)強制執行以下操作:

[6.5.6]如果兩個操作數都具有算術類型,則對它們執行常規的算術轉換。

但是,對於等價移位運算符,我們在等效部分中沒有看到這樣的短語。 我們最接近的是:

[6.5.7]對每個操作數執行整數提升。 結果的類型是提升后的左操作數的類型。

但是, 整數提升另一回事 -他們(基本上)說,將小於[unsigned] int任何類型都轉換為[unsigned] int

因此,編譯器在此處發出警告是正確的。 (而且,我敢肯定,您可以猜到,解決方案是對左側操作數執行顯式轉換;)


1.為了這個答案,我考慮使用C11(特別是N1570 )規范。 行為至少與C99相同。

這個答案表明我可以提升兩個操作數中的任何一個,並且整個表達式將長時間轉換為無符號,但是這可能是錯誤的。

它是。

該標准說:

6.5.7 按位移位運算符
對每個操作數執行整數提升。 結果的類型是提升后的左操作數的類型。 如果右操作數的值為負或大於或等於提升的左操作數的寬度,則行為不確定

這意味着您需要強制轉換左操作數,而強制轉換右操作數在這里不會發生任何變化。

您鏈接的答案具有誤導性。 似乎建議您加寬任何一個操作數,它將觸發另一操作數自動轉換為普通(更寬)類型。 對於C中的大多數二進制運算符而言,這是正確的。但是,對於移位運算符而言,則並非如此。

在這方面,C中的移位運算符實際上很特殊 它們的行為不對稱。 將右操作數的類型更改為較寬的類型不會觸發將左操作數轉換為右操作數的類型,並且不會影響結果類型。 結果類型始終由左操作數的(可能是提升的)類型定義。

在您的情況下,您必須專門將操作數轉換為unsigned long long類型。

左右移位運算符的結果與左操作數的類型相同。 因此,正確的操作數的類型不會影響結果的類型。

您需要將左操作數強制轉換為unsigned long long以獲得所需的結果。

即使我將每個正確的操作數都強制轉換為unsigned long long ,警告仍然存在。 uint8_t << uint64_t是否應該具有這樣的隱式轉換: (uint64_t) uint8_t << uint64_t

沒有。

這個答案表明我可以提升兩個操作數中的任何一個,整個表達式都將轉換為unsigned long long ,但這可能是錯誤的。

我明白了您為什么認為鏈接的答案這么說,但是它證明了使用unsigned long long類型的常量作為操作數。 那部分是正確的。 在某種程度上,答案表明可以通過在右側使用更大的類型來實現相同的目的,這具有誤導性。

該標准規定:

對每個操作數執行整數提升。 結果的類型是提升后的左操作數的類型。 如果右操作數的值為負或大於或等於提升的左操作數的寬度,則行為是不確定的。

C2011,6.5.7 / 3

注意清楚,結果表達式的類型是由左操作數的類型來確定唯一,並且它是相對於(促進)型的左操作數的可以觸發這個特定undefinedness規定右操作數的

您正在將uint8_t左移。 整數提升將在左邊的操作數上執行,結果是int類型的值。 假設您的int為32位寬,左移32位或更多位會產生未定義的行為,並且在某些情況下,由於它是帶符號的 ,而不是無符號的int,因此您可能會得到其他未定義的行為。

通過強制轉換操作數來糾正此問題。 例如, (uint64_t) u[7] << 56

暫無
暫無

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

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