C shift表达式是否具有无符号类型?为什么Splint会警告右转?

问题描述 投票:17回答:3

对于以下程序:

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工作。

我的问题是:

  1. C标准是否对比特移位的结果类型提出任何要求?
  2. 编译器吗?
  3. 如果没有,为什么Splint会发出此警告?
c language-lawyer code-analysis bit-shift splint
3个回答
17
投票

不。标准说,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;
}

17
投票

这是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,引用了这个问题。


2
投票

C99至C17标准说:

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

由于valueint,它不需要升级,“升级左操作数”的类型是int<<的结果类型是相同的。

C89 / C90说的相同,只是用“整数”代替“整数”。

© www.soinside.com 2019 - 2024. All rights reserved.