[英]Conversion Warning with Bitwise Or and Casted Operands
代碼片段 1(如下所示)產生以下 -Wconversion 警告:
debug_Wconversion.c:10:57: warning: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Wconversion]
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
^
代碼片段 2 和 3 不會產生 -Wconversion 警告。
代碼片段 1:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
代碼片段 2:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
uint16_t leftOrOperand;
uint16_t rightOrOperand;
leftOrOperand = ((uint16_t) (((uint16_t) byte1) & 0x0050));
rightOrOperand = ((uint16_t) byte2);
result = leftOrOperand | rightOrOperand;
代碼片段 3:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = (uint16_t) (((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2));
為什么第一個代碼片段會產生警告,而其他代碼片段不會? 導致警告的具體原因是什么?
我覺得這很令人困惑。 盡管顯式轉換了操作數,但第一個片段中的警告暗示在按位或操作中發生了整數提升。 第二個片段演示了按位或操作本身不會導致整數提升。 如果保留操作順序,第三個代碼段執行與第一個代碼段相同的操作,但在分配結果變量之前轉換按位或的結果。 很明顯,我無法理解強制轉換和按位或操作之間的相互作用。 任何幫助澄清我的理解將不勝感激!
其他可能相關的信息:
提前致謝!
按位或運算符|
和按位 AND 運算符&
對兩個操作數執行整數提升。 操作數之一是強制轉換的結果這一事實不會改變這一點。
-Wconversion
標志對於它警告的內容往往有點-Wconversion
。 給定一個 32 位的int
,從uint16_t
到int
的轉換不會改變它的值。
C 標准確實指定int
的最小范圍是 -32767 到 32767,因此具有此限制的實現可能會看到值更改,盡管您將很難找到運行 gcc 的系統,這是案件。
然而,這個特殊的警告被演員壓制了。 從手冊頁:
-W轉換
警告可能會改變值的隱式轉換。 這包括實數和整數之間的轉換,如“abs (x)”,當“x”為“double”時; 有符號和無符號之間的轉換,如“unsigned ui = -1”; 並轉換為較小的類型,例如“sqrtf (M_PI)”。 不要警告像 "abs ((int) x)" 和 "ui = (unsigned) -1" 這樣的顯式轉換,或者如果像 "abs (2.0)" 那樣的轉換沒有改變值。 可以使用 -Wno-sign-conversion 禁用有關有符號和無符號整數之間轉換的警告。
對於 C++,還警告混淆用戶定義轉換的重載解析; 和從不使用類型轉換運算符的轉換:轉換為“void”、相同類型、基類或對它們的引用。 除非顯式啟用 -Wsign-conversion,否則 C++ 中默認禁用有關有符號和無符號整數之間轉換的警告。
為什么第一個代碼片段會產生警告,而其他代碼片段不會? 導致警告的具體原因是什么?
((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2)
((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2)
是分配給uint16_t
的int
。
((uint16_t) (((uint16_t) byte1) & 0x0050))
是一個uint16_t
。
((uint16_t) byte2)
也是一個uint16_t
。
uint16_t | uint16_t
uint16_t | uint16_t
在|
之前首先將操作數提升為int
.
代碼正在為uint16_t
分配一個int
- 因此發出警告。
在第二個片段中,編譯器更好地理解 or'ing 兩個uint16_t
(結果也是int
)不會導致向下轉換為uint16_t
的轉換問題。 第一個只是有點太復雜,編譯器無法推斷出任何問題。
在第三場比賽中,最后的演員陣容消除了任何向下轉換問題。
替代方法:對uint16_t
等無符號類型使用unsigned
常量: 0x0050u
和unsigned
數學。
uint8_t byte1 = 0xF0u;
uint8_t byte2 = 0x0Fu;
// v-------------v unsigned result
// v-----v unsigned constant
uint16_t result = (byte1 & 0x0050u) | byte2;
// ^-----------------------^ unsigned result
// ^--------------------------------^ initializing: unsigned to uint16_t
討厭的編譯器可能仍然會抱怨縮小初始化。
// Non-cast alternative
uint16_t result = UINT16_MAX & ((byte1 & 0x0050u) | byte2);
// Cast alternative
uint16_t result = (uint16_t) ((byte1 & 0x0050u) | byte2);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.