我想存储一个寄存器值并像下面那样做
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
六角值将变为负数。
所以我想知道如何正确地将负值转换为无符号类型?有什么建议吗?
但是当我执行
代码时,QAC 会发出像这样的警告TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));
Constant: Negative value cast to an unsigned type
首先,C 不反对将负整数值转换为无符号类型。行为是明确定义的。反对的是 MISRA。事实上,MISRA 从根本上反对将
~
应用于有符号整数类型的表达式,and 它反对将有符号整数类型的复合表达式转换为不同的“基本类型类别”,例如无符号整数。我不确定 QAC 的确切来源,但 MISRA 不关心被转换的表达式的值是否实际上是负数。
要做的事情是首先从一个无符号整数开始。您可以通过在常量后缀
u
或U
来做到这一点:0x00000004u
。或者,stdint.h
包含用于编写显式宽度类型常量的宏,并且通过使用其中适当的一个,您可以解决签名问题and避免强制转换:
#define CHECK_FLAG (UINT32_C(0x00000004))
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
如何正确做负值...
使用掩码,最好使用 unsigned 常量(那时没有负值)。不需要
()
,但也无害。
通常一个 cast 表示弱代码。
// #define CHECK_FLAG (0x00000004)
#define CHECK_FLAG 0x00000004U
// TEST_REGISTER->u32Register &= (uint32)(~(CHECK_FLAG));
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
在使用
~
运算符之前进行转换,或者将 CHECK_FLAG 定义为带有转换的 uint32 或通过向文字添加“u”以指定它是无符号文字。
~((uint32)CHECK_FLAG)
或
#define CHECK_FLAG ((uint32)0x00000004)
#define CHECK_FLAG (0x00000004u)
请参阅此页面:http://port70.net/~nsz/c/c11/n1570.html#6.4.4.1 C 中的不同后缀
没有后缀的文字总是被解释为
int
。那么让我们来看看当你写的时候会发生什么:
(uint32)(~(CHECK_FLAG))
CHECK_FLAG,它是文字
4
,因此在反转位时表现为带符号的 int,由于位反转而变成负值。
(uint32)(-5)
现在您将负值转换为无符号类型,编译器会警告您。
如果将 uint32 强制转换为 before 反转(或使用无符号文字开头),则反转不会导致负值,因为在反转位时变量已经无符号,并且无符号值不能变得消极。
您的 MISRA 检查器应该已经在
#define CHECK_FLAG (0x00000004)
处发出警告。这需要有一个 U
/u
后缀才能符合 MISRA,这就是这里的实际问题。
其他一些注意事项:
整数常量周围的括号没有任何意义(但如果将其与其他宏一起使用可能会出现问题。)
在十六进制数前添加一堆
0000....
没有任何意义,只会让程序员感到困惑。当涉及到十六进制整数常量时,C 有点破烂/厚颜无耻。假设 32 位系统,那么 0x00000004
是 int
类型,0x4
是 int
类型,但是 0x80000000
是 unsigned int
类型,而 0x100000000
是 long
或 long long
类型。
因此很容易写出细微的错误。作为一些 RL 轶事,我曾经接手一个 8 位 16 位
int
的失败项目,他们养成了像这样输入零的习惯,自欺欺人地认为他们得到了 32 位数字。事实上,该项目实际上包含 16 位 int
、16 位 unsigned int
和 32 位 long
的混合,这是整个程序被破坏的主要原因之一。
因此正确的代码应该是:
#define CHECK_FLAG 0x4u
...
TEST_REGISTER->u32Register &= ~CHECK_FLAG;
在这种情况下,括号垃圾邮件对 MISRA 合规性没有影响 - 它只是膨胀所以我删除了它。也不再需要强制转换,因为表达式的所有操作数都是无符号的,MISRA 称之为“本质上无符号”,因此不需要强制转换。