对于以下程序:
int main(void)
{
int value = 2;
int result = value >> 1U;
return result;
}
...Splint 3.1.2 发出警告:
splint_test.c: (in function main)
splint_test.c:4:18: Variable result initialized to type unsigned int, expects
int: value >> 1U
To ignore signs in type comparisons use +ignoresigns
Splint 似乎声称将有符号整数右移的表达式具有无符号整数的类型。然而,我能在 ANSI C90 标准中找到的是:
The result of
E1 >> E2
isE1
right-shiftedE2
bit positions. IfE1
has an unsigned type or ifE1
has a signed type and a nonnegative value, the value of the result is the integral part of the quotient ofE1
divided by the quantity, 2 raised to the powerE2
.
此代码的主要目标是带有主要是 C90 编译器的嵌入式系统。但是,我对编写符合标准的代码很感兴趣。我一直在 C99 模式下对 GCC 和 Clang 进行测试,以便 restrict
起作用。
我的问题是:
- C 标准是否对位移结果的类型做出任何声明?
- 编译器呢?
- 如果不是,为什么 Splint 会发出此警告?
最佳答案
这是 Splint 中的一个错误。 Splint 错误地假定 e1 << e2
的类型是ctype_wider(te1, te2)
.正确的类型应该是 te1
.
buggy code starts here通过对像 &
这样的按位运算符使用相同的代码路径, |
和 ^
,以及 <<
和 >>
运营商。
actual bug is at the end of that code ,它假定对于所有这些按位二元运算符,返回类型都是 ctype_wider(te1, te2)
.
我有opened a bug在 Splint 的 GitHub 问题跟踪器上,引用了这个问题。
2021 年 2 月更新:
NetBSD's lint says在传统的 C 中,位移运算符将通常的算术转换应用于它们的操作数:
/* Make sure both operands are of the same type */
if (mp->m_balance_operands || (tflag && (op == SHL || op == SHR)))
balance(op, &ln, &rn);
代码解释:
-
tflag
是检查传统 C 程序的标志,而不是 C90 或 C99 -
mp->m_balance_operands
是false
对于位移运算符,定义为 in this table ,b
中间列 -
balance
performs the usual arithmetic conversions
这是 C90 中的一个变化。因此,Splint 代码对于传统 C 可能是正确的,也许它只是没有针对 C90 或 C99 进行更新。
关于c - C 移位表达式是否具有无符号类型?为什么 Splint 会警告右移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55673029/