C移位表达式是否具有无符号类型?为什么夹板会警告右移?

det*_*tly 17 c code-analysis splint bit-shift language-lawyer

对于以下程序:

int main(void)
{
    int value = 2;
    int result = value >> 1U;
    return result;
}
Run Code Online (Sandbox Code Playgroud)

... 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
Run Code Online (Sandbox Code Playgroud)

Splint似乎声称有符号整数右移的表达式具有无符号整数的类型。但是,我可以在ANSI C90标准中找到的全部是:

结果E1 >> E2E1右移位E2位置。如果E1具有无符号类型或E1具有符号类型和非负值,则结果的值是商E1除以数量2的幂的整数部分E2

此代码的主要目标是带有大多数C90编译器的嵌入式系统。但是,我对编写符合标准的代码感兴趣。我一直在以C99模式在GCC和Clang上进行测试,因此可以restrict正常工作。

我的问题是:

  1. C标准是否对移位结果的类型提出任何要求?
  2. 做编译器吗?
  3. 如果不是,为什么夹板会发出此警告?

PSk*_*cik 17

否。标准说,移位的类型是左操作数的类型,提升为: 6.5.7p3

...结果的类型是提升后的左操作数的类型。...

您的工具必​​须混淆,使用通常的算术转换来推断类型,该算术转换适用于大多数二进制运算符,但不适用于<<and >>

您还可以通过插入_Generic基于- 类型的断言并观察编译器接受它来验证类型为int :

int main(void)
{
    int value = 2;
    int result = _Generic(value >> 1U, int: value>>1U); //compiles, the type is int
    return result;
}
Run Code Online (Sandbox Code Playgroud)


Rol*_*lig 17

这是夹板中的错误。夹板错误地假定类型e1 << e2ctype_wider(te1, te2)。正确的类型是just te1

bug的代码从这里开始使用相同的代码路径,位运算符一样&|并且^,以及对于<<>>运营商。

实际的错误是在代码的结束,即假设所有这些按位二进制运算符,返回类型为ctype_wider(te1, te2)

我在Splint的GitHub问题跟踪器上打开了一个错误,引用了这个问题。