用 klocwork 分析时,下面这行
pTxData[index] = ( UINT8_C(0) << UINT8_C(4) );
给出错误
按位运算的操作数类型为“有符号字符”而不是“无符号整数”
我已经通过删除任何问题将问题减少到最低限度,#define
并且完全不知道为什么会发生这种情况。
对于那些不知道的人,UINT8_C
是一个 C 标准宏1)用于获取类型的整数常量uint_least8_t
而不是默认的int
.
因此UINT8_C(0)
等价于(uint_least8_t)0
。这将是一个小整数类型。因此,当作为左操作数传递给 时,它会受到整数提升2)<<
的影响。提升后它最终成为类型int
,相当于只是写作0
。
您永远不应该将带符号的操作数与按位运算符一起使用,因此这是错误消息的核心原因。更正后的代码应如下所示0u << 4
。尽管除了自记录代码之外,这段代码当然对任何东西都毫无意义。(当然,将值 0 移动总是无害的。)
UINT8_C
在右边的操作数上使用<<
是无稽之谈 - 该操作数不参与结果的任何类型提升。如果您需要使用无符号文字来满足编码标准,请使用4u
. 值得注意的是,在您实际上不需要无符号类型的情况下,像 MISRA-C 这样的标准不需要u
后缀——这是工具误报的常见来源。
摘要 - 使用这个:
pTxData[index] = 0u << 4;
此外,Klockwork 给出了不正确的诊断信息。您表达式中的运算符既可能等同于该工具所说的,unsigned char
也绝对signed char
不像该工具所说的那样。
1)在 C99 7.18.4.1中引入。
2)见隐式类型提升规则
在大多数表达式中,等级小于int
get 的整数类型转换为int
(如果int
可以无损失地表示所有值)或unsigned int
(否则)。
为了简化一点,请考虑将等级与类型中的位数相对应,位数越多,等级越高(有关该术语的明确处理,请参阅语言参考(例如,您可以从这里开始))。
这里似乎是这种情况,由UINT8_C()
(可能unsigned char
是伪装的)返回的类型的等级小于int
,所以你最终有一个带符号的类型。
现在,警告的原因是在所有情况下都没有很好地定义转换有符号整数类型。向左移动负值或在移动时溢出相当于未定义的行为,这意味着如果遇到这两个条件中的任何一个,程序可能会以多种方式出现异常。(转移无符号类型时溢出是合法的,你会得到一个截断的值)。
此外,班次计数不能为负数。
但是,如果这是确切的代码,则警告是不必要的,因为显然将 0 左移 4 个位置是完全安全的。如果您使用变量而不是常量,编译器(或工具)并不总是能够推断出这种转变的安全性,在这种情况下,您应该注意警告并以这样的方式重写您的代码未定义的行为或警告。