簡體   English   中英

按位或和強制轉換操作數的轉換警告

[英]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));

為什么第一個代碼片段會產生警告,而其他代碼片段不會? 導致警告的具體原因是什么?

我覺得這很令人困惑。 盡管顯式轉換了操作數,但第一個片段中的警告暗示在按位或操作中發生了整數提升。 第二個片段演示了按位或操作本身不會導致整數提升。 如果保留操作順序,第三個代碼段執行與第一個代碼段相同的操作,但在分配結果變量之前轉換按位或的結果。 很明顯,我無法理解強制轉換和按位或操作之間的相互作用。 任何幫助澄清我的理解將不勝感激!

其他可能相關的信息:

  • gcc (GCC) 4.8.5 20150623(我無法升級,但這似乎也發生在較新的版本上)
  • -std=c11
  • -Wconversion 警告存在於默認優化(未提供設置)和禁用優化(-O0)

提前致謝!

按位或運算符| 和按位 AND 運算符&對兩個操作數執行整數提升。 操作數之一是強制轉換的結果這一事實不會改變這一點。

-Wconversion標志對於它警告的內容往往有點-Wconversion 給定一個 32 位的int ,從uint16_tint的轉換不會改變它的值。

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_tint

((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常量: 0x0050uunsigned數學。

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.

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