对于以下程序:
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标准中找到的是:
E1 >> E2
的结果是E1
右移E2
位位置。如果E1
具有无符号类型或者如果E1
具有有符号类型和非负值,则结果的值是E1
除以数量的商的整数部分,2增加到幂E2
。
此代码的主要目标是具有大多数C90编译器的嵌入式系统。但是,我有兴趣编写符合标准的代码。我一直在CCC模式下测试GCC和Clang,以便restrict
工作。
我的问题是:
不。标准说,bitshift的类型是左操作数的类型,提升:6.5.7p3
...结果的类型是提升的左操作数的类型。 ...
您的工具必须混淆,通过常规算术转换推断类型,这适用于大多数二元运算符,但不适用于<<
和>>
。
您还可以通过插入基于_Generic
的类型断言并观察that compilers accept it来验证类型是否为int:
int main(void)
{
int value = 2;
int result = _Generic(value >> 1U, int: value>>1U); //compiles, the type is int
return result;
}
这是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)
。
我在Splint的GitHub问题跟踪器上有opened a bug,引用了这个问题。
C99至C17标准说:
对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。
由于value
是int
,它不需要升级,“升级左操作数”的类型是int
,<<
的结果类型是相同的。
C89 / C90说的相同,只是用“整数”代替“整数”。