gcc如何处理-Wtype-limits?

7

我在使用gcc 4.4.5-Wtype-limits选项进行一个小代码片段的测试。

#include <assert.h>
#include <limits.h>
#include <stdint.h>

int main(void)
{
    /* With other values of v, the behavior of the compiler is the same. */
    uint16_t v = 0; 
    assert((unsigned int)INT_MAX < (unsigned int)v); /* l. 7 */
    return 0;
}

然后,编译器给出了以下警告:

main.c:7: warning: comparison is always false due to limited range of data type

然而,据我所知,INT_MAX 可能等于+32767(来自 C11 (n1570), § 5.2.4.2.1 Sizes of integer types <limits.h>)。在这种情况下,变量v可以容纳值INT_MAX+1,并且assert中的表达式将被评估为1

因此,我可以看到两个问题:

  • GCC考虑了我的架构,因为实际上INT_MAX不等于+32767。在这种情况下,它会减少-Wtype-limits对我的好处。
  • 这是一个bug。

让我想到第二个选项的是以下代码,使用相同的选项不会产生任何警告。

#include <assert.h>
#include <limits.h>
#include <stdint.h>

int main(void)
{
    assert((unsigned int)INT_MAX < (unsigned int)UINT16_MAX);
    return 0;
}

那么,正确答案是什么?

PS:顺便说一下,我必须因为我的旧版本gcc而道歉。也许下一个版本的行为会有所不同。


你想让gcc对INT_MAX的任何可能值都发出警告吗?此外,我预计这一切都是在预处理之后完成的,因此在检查此警告时,它可能只看到一个变量和一个整数常量之间的比较。 - David Brown
1个回答

6

GCC会考虑类型的实际已知限制。它知道在您的情况下int的宽度超过16位,因此会发出警告。

以下内容不会收到警告:

#include <assert.h>
#include <limits.h>
#include <stdint.h>

int main(void)
{
    assert((unsigned int)INT_MAX < (unsigned int)UINT16_MAX);
    return 0;
}

因为标准在7.20.2(2)中提到:
每个定义的宏实例都应该被替换为一个适用于在#if预处理指令中使用的常量表达式,且这个表达式应该与按整数提升转换后成为对应类型对象的表达式具有相同的类型。
因此,在32位宽度的int中,宏UINT16_MAX是一个int,因此涉及类型的限制并不能保证比较总是为false(或true)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接