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

标签 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 标准中找到的是:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity, 2 raised to the power E2.

此代码的主要目标是带有主要是 C90 编译器的嵌入式系统。但是,我对编写符合标准的代码很感兴趣。我一直在 C99 模式下对 GCC 和 Clang 进行测试,以便 restrict 起作用。

我的问题是:

  1. C 标准是否对位移结果的类型做出任何声明?
  2. 编译器呢?
  3. 如果不是,为什么 Splint 会发出此警告?

最佳答案

这是 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) .

我有opened a bug在 Splint 的 GitHub 问题跟踪器上,引用了这个问题。


2021 年 2 月更新:

NetBSD's lint says在传统的 C 中,位移运算符将通常的算术转换应用于它们的操作数:

    /* Make sure both operands are of the same type */
    if (mp->m_balance_operands || (tflag && (op == SHL || op == SHR)))
        balance(op, &ln, &rn);

代码解释:

这是 C90 中的一个变化。因此,Splint 代码对于传统 C 可能是正确的,也许它只是没有针对 C90 或 C99 进行更新。

关于c - C 移位表达式是否具有无符号类型?为什么 Splint 会警告右移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55673029/

相关文章:

c# - CA2204 警告在字符串文字中提及类型名称

c - 在C中使用free()后出现段错误

c++ - 什么创建了堆栈?

c - 如何在C中动态调整结构数组的大小

c++ - 为什么聚合推导中不支持大括号初始化列表但支持大括号省略?

Javascript 代码分析和最佳实践

java - 查找事件分派(dispatch)线程违规

编译器定义,将函数重定向到不同的名称

c++ - malloc分配的对象动态类型是什么?

c - 序列点和评估顺序