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

时间:2019-04-14 07:38:26

标签: c language-lawyer code-analysis bit-shift splint

对于以下程序:

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可以正常工作。

我的问题是:

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

3 个答案:

答案 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标准说:

  

对每个操作数执行整数提升。结果的类型是提升后的左操作数的类型。

由于valueint,因此不需要提升,并且“提升的左操作数”的类型为int,并且<<的结果类型为一样。

C89 / C90表示相同的内容,只是用“整数”代替了“整数”。