如何在C中正确地将负值转换为无符号类型?

wlsrxk51  于 2023-04-29  发布在  其他
关注(0)|答案(4)|浏览(288)

我想存储一个寄存器值,并执行如下所示的bitwise NOT operator

typedef union TEST_REG {
  uint32_t                         u32Register;
  uint8_t                          Byte[4];
  uint16_t                         hword[2];
} tst_reg;

#define TEST_REGISTER              ((volatile tst_reg*) 0x7023100CUL) // Register

下面是存储值的示例代码

#define CHECK_FLAG                  (0x00000004)
TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG));

但是当我执行TEST_REGISTER->u32Register &= (uint32_t)(~(CHECK_FLAG));代码时,QAC抛出一个警告,如

Constant: Negative value cast to an unsigned type

我明白如果我们做一个NOT (~) operator,Hexa值将变为负数。
所以我想知道如何正确地将负值转换为无符号类型?有什么建议吗?

neskvpey

neskvpey1#

但是当我执行TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));代码时,QAC抛出一个警告,如

Constant: Negative value cast to an unsigned type

首先,C不反对将负整数值转换为无符号类型。行为定义明确。反对的是MISRA。事实上,MISRA从根本上反对将~应用于有符号整数类型的表达式,* 并且 * 它反对将有符号整数类型的复合表达式转换为不同的“基本类型类别”,例如无符号整数。我不确定QAC的确切来源,但MISRA并不关心被转换的表达式的值是否实际上是负的。
要做的事情是首先从一个无符号整数开始。您可以通过添加uU来实现这一点:0x00000004u。或者,stdint.h包含用于写入显式宽度类型常量的宏,通过使用其中适当的一个,您可以解决符号问题 * 和 * 避免强制转换:

#define CHECK_FLAG                  (UINT32_C(0x00000004))
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
yvt65v4c

yvt65v4c2#

如何正确对待负价值..
使用掩码时,最好使用 unsigned 常量(这样就没有负值了)。()是不需要的,但也不是有害的。
通常,cast 表示弱代码。

// #define CHECK_FLAG                  (0x00000004)
#define CHECK_FLAG                  0x00000004U
// TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
vuktfyat

vuktfyat3#

在使用~运算符之前进行强制转换,或者通过强制转换将CHECK_FLAG定义为uint32,或者向文本添加“u”以指定它是无符号文本。

~((uint32)CHECK_FLAG)

#define CHECK_FLAG ((uint32)0x00000004)
#define CHECK_FLAG (0x00000004u)

查看此页面: www.example.com 中的不同后缀。
没有后缀的文字总是被解释为int。让我们来看看当你写的时候会发生什么:
(uint32)(~(CHECK_FLAG))
CHECK_FLAG是文字4,因此在反转位时表现为有符号int,由于位反转而变为负值。
(uint32)(-5)
现在,您将一个负值转换为无符号类型,编译器会警告您。
如果在反转之前将uint32强制转换为 *(或使用无符号文字开始),则反转不会导致负值,因为在反转位时变量已经是无符号的,并且无符号值不能变为负值。

nwlqm0z1

nwlqm0z14#

您的MISRA检查器应该已经在#define CHECK_FLAG (0x00000004)处给予警告。这需要有一个U/u后缀才能兼容MISRA,这就是这里的实际问题。
其他一些值得注意的事情:

  • 整数常量周围的括号没有任何用处(但在与其他宏一起使用时可能会出现问题)。)
  • 在十六进制数字前面添加一串0000....除了使程序员感到困惑之外没有任何意义。当涉及到十六进制整数常量时,C是一种破碎的/厚脸皮的。假设32位系统,则0x00000004的类型为int0x4的类型为int,但0x80000000的类型为unsigned int0x100000000的类型为longlong long

因此很容易编写细微的bug。作为一些RL轶事,我曾经接手过一个8位的16位int项目,他们习惯于像这样输入零,欺骗自己,以为他们得到的是32位数字。而事实上,该项目实际上包含了16位int,16位unsigned int和32位long的混合,这是整个程序被破坏的主要原因之一。
因此,正确的代码应该是:

#define CHECK_FLAG 0x4u
...
TEST_REGISTER->u32Register &= ~CHECK_FLAG;

在这种情况下,括号垃圾邮件对MISRA合规性没有影响-它只是膨胀,所以我删除了它。因为表达式的所有操作数都是无符号的,MISRA称之为“本质上是无符号的”,所以不再需要强制转换。

相关问题