提问者:小点点

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


我正在编写一个函数库,可以安全地在各种数字类型之间进行转换或尝试。我的意图大致相当于create-有用-库和learn-C-edge-情况。

我的int-to-size_t函数触发了一个GCC-Wtype-限制警告,该警告声称我不应该测试int是否大于SIZE_MAX,因为它永远不会是真的。(另一个将int转换为ssize_t的函数会产生关于SSIZE_MAX的相同警告。)

我的MCVE,有额外的评论和婴儿步骤,是:

#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;
}

我从Linux2.6.34的GCC4.4.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

…也是从GCC4.8.5到Linux3.10.0:

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 */
     ^

这些警告对我来说似乎没有道理,至少在一般情况下没有。(我不否认在硬件和编译器的某些特定组合上,比较可能“总是错误的”。)

C 1999标准似乎不排除int大于SIZE_MAX的可能性。

部分6.5.3.4sizeof运算符根本不涉及size_t,除了将其描述为中定义的

部分“7.17常用定义<代码>

第7.18.3节其他整数类型的限制更有帮助-它将size_t的限制定义为:

SIZE_MAX65535

…意味着SIZE_MAX可以小到65535。int(有符号或无符号)可能比这大得多,具体取决于硬件和编译器。

无符号intvs.size_t的公认答案似乎支持我的解释(强调):

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

这个答案引用了我已经引用的C标准的“第7.17节”。

我的搜索出现了Open Group的论文“数据大小中立性和64位支持”,该论文在“64位数据模型”下声称(强调添加):

ISO/IEC 9899:1990,编程语言-C(ISOC)对短intint长int指针的定义故意模糊[…]唯一的约束是ints必须不小于s,longs必须不小于ints,并且size_t必须表示实现支持的最大无符号类型。[…]基本数据类型之间的关系可以表示为:

(char)的大小

如果这是真的,那么针对SIZE_MAX测试int确实是徒劳的…但是这篇论文没有引用章节,所以我不知道它的作者是如何得出结论的。他们自己的“基本规范版本7”sys/type. h文档也没有解决这个问题。

我知道size_t不太可能比int更窄,但是C标准是否保证比较some_unsigned_int

这个问题有两个半重复,但它们都在问更一般的问题,比如size_t应该代表什么,什么时候应该/不应该使用。

>

  • "C中的size_t是什么?"没有解决size_t和其他整数类型之间的关系。它被接受的答案只是维基百科的引用,除了我已经找到的之外,它没有提供任何信息。

    "size_t的正确定义是什么?"开始时几乎重复了我的问题,但后来偏离了方向,询问何时应该使用size_t以及为什么引入它。它作为上一个问题的重复而被关闭。


  • 共3个答案

    匿名用户

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

    GCC警告不是指理论上的可能性。它是检查特定的硬件平台和特定的编译器和运行时。这意味着它有时会在试图可移植的代码上触发。(还有其他情况下,可移植代码会触发可选的GCC警告。)这可能不是你希望警告能做的,但可能有些用户的期望与实现的行为完全匹配,标准没有为编译器警告提供任何指导。

    正如OP在评论中提到的,与此警告相关的历史由来已久。该警告是在3.3.2版本左右(2003年)引入的,显然不受任何-W标志的控制。这被一个用户报告为12963bug,他显然和你一样认为该警告不鼓励可移植编程。正如bug报告中所示,各种GCC维护者(和社区的其他知名成员)发表了强烈但相互矛盾的意见。(这是开源bug报告中的常见动态。)几年后,决定用一个标志来控制警告,并且默认情况下或作为-Wall的一部分不启用该标志。与此同时,-W选项已重命名为-Wextra,并且新创建的标志(-Wtype-限制)已添加到-Wextra集合中。对我来说,这似乎是正确的分辨率。

    这个答案的其余部分包含我个人的观点。

    -Wall,如GCC手册中所述,实际上并没有启用所有警告。它启用了那些“关于一些用户认为有问题的结构的警告,并且很容易避免(或修改以防止警告),即使与宏结合使用。”还有许多GCC可以检测到的其他情况:

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

    这些区别有些武断。例如,每次GCC决定“建议圆括号”时,我都必须咬紧牙关

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

    我知道有些人认为,仅仅是GCC知道如何警告某些情况,就足以要求采取行动来避免这种警告。每个人都有权做出自己的风格和美学判断,这样的程序员在他们的构建标志中添加-Wextra是正确的,也是公正的。然而,我不属于那种人。在项目的给定点,我会尝试启用大量可选警告的构建,并考虑是否根据报告修改我的代码,但我真的不想在每次重建文件时都花时间思考非问题。-Wtype-limited标志对我来说属于这一类。

    匿名用户

    没有什么要求size_t的最大值大于int

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

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

    匿名用户

    我同意Remer. D的解释。

    size_t被指定为标准的无符号整数,但是标准并没有限制它相对于任何一个整数的大小,只是说它必须至少能够容纳65535

    因此,它的大小可以比无符号int更小、相等或更大。