size_t(SIZE_MAX)的最大值是否相对于其他整数类型定义了?

时间:2017-10-01 03:01:48

标签: c types integer limit

我正在编写一个函数库,可以安全地在各种数字类型之间进行转换或者尝试死亡。 我的意图大致相当于创建有用库和学习C边缘案例。

我的int - 至 - size_t功能正在触发GCC -Wtype-limits警告声称我不应该测试int是否大于{{1}因为它永远不会是真的。 (将SIZE_MAX转换为int的另一项功能会产生与ssize_t相同的警告。)

我的MCVE,附加评论和小步骤,是:

SSIZE_MAX

编译器警告

我在Linux 2.6.34上收到GCC 4.4.5的类似警告:

#include <stdint.h>  /* SIZE_MAX */
#include <stdlib.h>  /* exit EXIT_FAILURE size_t */

extern size_t i2st(int value) {
    if (value < 0) {
        exit(EXIT_FAILURE);
    }
    // Safe to cast --- not too small.
    unsigned int const u_value = (unsigned int) value;
    if (u_value > SIZE_MAX) {  /* Line 10 */
        exit(EXIT_FAILURE);
    }
    // Safe to cast --- not too big.
    return (size_t) u_value;
}

...以及Linux 3.10.0上的GCC 4.8.5:

$ gcc -std=c99 -pedantic -Wall -Wextra -c -o math_utils.o math_utils.c

math_utils.c: In function ‘i2st’:
math_utils.c:10: warning: comparison is always false due to limited range of data type

这些警告对我来说似乎不合理,至少在一般情况下并非如此。 (我不否认比较可能是 &#34;总是假的#34; 关于硬件和编译器的某些特定组合。)

C标准

C 1999标准似乎并不排除math_utils.c: In function ‘i2st’: math_utils.c:10:5: warning: comparison is always false due to limited range of data type [-Wtype-limits] if (u_value > SIZE_MAX) { /* Line 10 */ ^ 大于int

节 &#34; 6.5.3.4 SIZE_MAX运营商&#34; 根本不解决sizeof,除非将其描述为 &#34;在size_t(和其他标题)中定义&#34;。

节 &#34; 7.17通用定义<stddef.h>&#34; 将<stddef.h>定义为 &#34; size_t运算符&#34;的结果的无符号整数类型。 (谢谢,伙计们!)

节 &#34; 7.18.3其他整数类型的限制&#34; 更有帮助--- 它定义了 &#34;限制sizeof&#34;为:

  

size_t SIZE_MAX

...意味着65535可以像一样为65535。 一个SIZE_MAX (签名或未签名) 可能远远大于此,具体取决于硬件和编译器。

堆栈溢出

接受的答案 &#34; unsigned int vs. size_t&#34; 似乎支持我的解释 (重点补充):

  

int类型可能大于,等于,或小于 size_t,您的编译器可能会对其进行假设以进行优化。

这个答案引用了相同的内容 &#34;第7.17节和#34; 我已经引用的C标准。

其他文件

我的搜索结果显示了Open Group的论文 &#34; Data Size Neutrality and 64-bit Support&#34 ;, 声称在 &#34; 64位数据模型&#34; (重点补充):

  

ISO / IEC 9899:1990,编程语言 - C(ISO C)   保留了unsigned intshort intintlong int故意模糊的定义   [...]   唯一的限制是pointer s必须不小于int s,short s必须不小于long s, {{1}必须表示实现支持的最大无符号类型。   [...]   基本数据类型之间的关系可表示为:

     
    

int&lt; = size_t&lt; = sizeof(char)&lt; = sizeof(short) = sizeof(int)

  

如果这是真的,那么针对sizeof(long)测试sizeof(size_t)确实是徒劳的...... 但是这篇论文并没有引用章节和经文,因此我无法说明其作者如何得出结论。 他们自己的 &#34;基本规范版本7&#34; sys/types.h docs 不要以这两种方式解决这个问题。

我的问题

我了解int不可能比SIZE_MAX更窄,但 C标准保证比较size_t 总是< / em>是假的? 如果是这样,在哪里?

不-重复

这个问题有两个半重复,但他们都在询问关于int应该代表什么以及何时应该/不应该使用的更多一般性问题。

  • &#34; What is size_t in C?&#34; 没有解决some_unsigned_int > SIZE_MAX和其他整数类型之间的关系。 它接受的答案只是维基百科的一句话,除了我已经发现的信息之外,它没有提供任何信息。

  • &#34; What is the correct definition of size_t?&#34; 开始几乎是我的问题的重复,但然后转向偏离,问 何时应使用size_t以及为何引入size_t。 它作为上一个问题的副本而被关闭。

3 个答案:

答案 0 :(得分:8)

当前的C标准不要求size_t至少与int一样宽,我对任何版本的标准都持怀疑态度。 size_t需要能够表示任何可能是对象大小的数字;如果实现将对象大小限制为24位宽,则size_t可以是24位无符号类型,无论int是什么。

GCC警告并未涉及理论上的可能性。它正在检查特定的硬件平台和特定的编译器和运行时。这意味着它有时会触发试图移植的代码。 (在其他情况下,可移植代码将触发可选的GCC警告。)这可能不是您希望警告可以执行的操作,但可能有用户的期望与实现的行为完全匹配,并且标准不提供任何指导对于编译器警告。

正如OP在评论中提到的那样,这个警告有很长的历史。警告是在版本3.3.2左右(2003年)中引入的,显然不受任何-W标志的控制。这被用户报告为bug 12963,用户显然觉得警告不鼓励便携式编程。从错误报告中可以看出,各种GCC维护者(以及社区中其他知名成员)都强烈感受到了相互冲突的意见。 (这是开源错误报告中的常见动态。)几年后,决定使用标志来控制警告,并且默认情况下不启用该标志或作为-Wall的一部分启用。与此同时,-W选项已重命名为-Wextra,新创建的标记(-Wtype-limits)已添加到-Wextra集合中。对我而言,这似乎是正确的解决方案。

本答复的其余部分包含我的个人意见。

如GCC手册中所述,

-Wall实际上并未启用所有警告。它允许那些警告“关于一些用户认为有问题的构造,并且容易避免(或修改以防止警告),甚至与宏一起使用。” GCC可以检测到许多其他条件:

  

请注意-Wall不暗示某些警告标志。他们中的一些人警告用户通常不认为有问题的结构,但有时您可能希望检查;其他人警告在某些情况下必要或难以避免的构造,并且没有简单的方法来修改代码以抑制警告。其中一些由-Wextra启用,但其中许多必须单独启用。

这些区别有些武断。例如,每次GCC决定“在'|''内”建议围绕'&amp;&amp;'括号时,我都要咬紧牙关。 (似乎没有必要在'+'内围绕'*'建议括号,这对我来说并没有什么不同。)但我认识到我们所有人都有不同的舒适度与运算符优先级,而不是全部海湾合作委员会关于括号的建议对我来说似乎过分了。

但总的来说,区别似乎是合理的。有些警告通常适用,并且-Wall启用了警告,始终,因为这些警告几乎总是需要采取措施纠正缺陷。还有其他警告可能在特定情况下有用,但也有很多误报;这些警告需要单独调查,因为它们并不总是(甚至经常)与代码中的问题相对应。

我知道有些人认为海湾合作委员会知道如何警告某些情况这一事实足以要求采取行动以避免这种警告。每个人都有权获得他们的风格和审美判断,这是正确的,只是这样的程序员将-Wextra添加到他们的构建标志中。然而,我并不在那群人中。在项目的给定点,我将尝试使用大量可选警告启用的构建,并考虑是否根据报告修改我的代码,但我真的不想花费我的开发时间每次重建文件时都要考虑非问题。 -Wtypes-limit标志属于我的类别。

答案 1 :(得分:4)

没有任何内容要求size_t的最大值大于intSIZE_MAX&lt; = INT_MAX这样的架构很少见,我怀疑GCC会支持任何

至于修复,您可以使用#if

#if INT_MAX > SIZE_MAX
if (u_value > SIZE_MAX) {  /* Line 10 */
    exit(EXIT_FAILURE);
}
#endif

答案 2 :(得分:1)

我同意Remo.D's interpretation

size_t被指定为标准无符号整数,但标准不会相对于其中任何一个限制其大小,只是说它必须能够至少保持65535。< / p>

因此,它可以比unsigned int更小,相等或更大。