对于以下程序:
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编译器的嵌入式系统。但是,我对编写符合标准的代码感兴趣。我已经在C99模式下对GCC和Clang进行了测试,以便restrict
可以正常工作。
我的问题是:
答案 0 :(得分:17)
不。标准说位移的类型是左操作数的类型,被提升为: 6.5.7p3
...结果的类型是提升后的左操作数的类型。 ...
您的工具必须混淆,使用通常的算术转换来推断类型,该算术转换适用于大多数二进制运算符,但不适用于<<
和>>
。
您还可以通过插入基于_Generic
的 type assert 并观察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;
}
答案 1 :(得分:17)
这是夹板中的错误。夹板错误地认为e1 << e2
的类型为ctype_wider(te1, te2)
。正确的类型应该是te1
。
buggy code starts here通过对&
,|
和^
之类的按位运算符以及<<
和{ {1}}个运算符。
actual bug is at the end of that code,它假定对于所有这些按位二进制运算符,返回类型为>>
。
我在Splint的GitHub问题跟踪器上有opened a bug,引用了这个问题。
答案 2 :(得分:2)
C99至C17标准说:
对每个操作数执行整数提升。结果的类型是提升后的左操作数的类型。
由于value
是int
,因此不需要提升,并且“提升的左操作数”的类型为int
,并且<<
的结果类型为一样。
C89 / C90表示相同的内容,只是用“整数”代替了“整数”。