gcc 如何处理 -Wtype-limits?

md5*_*md5 5 c gcc types

我正在测试一个带有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;
}
Run Code Online (Sandbox Code Playgroud)

然后,编译器向我抛出以下警告:

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将能够保存 value INT_MAX+1,并且表达式 inassert将被评估为1

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

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

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

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

int main(void)
{
    assert((unsigned int)INT_MAX < (unsigned int)UINT16_MAX);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

那么,正确答案是什么?

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

Dan*_*her 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;
}
Run Code Online (Sandbox Code Playgroud)

因为标准7.20.2(2)中说:

任何定义的宏的每个实例都应替换为适合在#if预处理指令中使用的常量表达式,并且该表达式应与根据整数提升转换的相应类型的对象表达式具有相同的类型。

因此,对于 32 位宽的ints,宏UINT16_MAX是 an int,因此所涉及类型的限制不能保证比较始终为 false(或 true)。