使用 ssize_t 与 int

Posted

技术标签:

【中文标题】使用 ssize_t 与 int【英文标题】:Using ssize_t vs int 【发布时间】:2013-10-14 00:22:28 【问题描述】:

代码

我有一个函数,我可以用 一种 四种可能的方式编写它:

    int do_or_die(int retval);
    int do_or_die(ssize_t retval);
    ssize_t do_or_die(int retval);   
    ssize_t do_or_die(ssize_t retval);   

然后它会被两种库函数调用:

    written = do_or_die(write(...)); // POSIX write returns ssize_t
    printed = do_or_die(printf(...)); // printf returns int

问题

我应该使用哪个原型? 我应该给writtenprinted提供什么类型?

我希望拥有最强大和最标准的代码,同时仍然只有一个 do_or_die 函数。

在这种情况下我使用的是 C99,但如果 C11 的答案不同,那么我也想知道这一点,以备将来使用。

【问题讨论】:

由于ssize_t 可能比int 更宽,您可能应该使用第四个原型。 @PaulR 是否有保证,或者int 也可能比ssize_t 更宽? @delnan:我不认为这是可能的,尽管他们可能是平等的。 @PaulR 好吧,我可以想象一个 int 更宽的体系结构:分段内存是 16 位 x86(所以 ssize_t 是 16 位),具有 32 位整数。问题实际上是相关标准(某些版本的 C,在本例中为 POSIX)是否能保证任何事情。 感谢大家的洞察!我认为在实际代码中我会执行int do_or_die(intmax_t retval);,如果它不适合则直接退出,因为由于系统的某些物理限制,不适合int 的返回值纯粹是理论上的。 【参考方案1】:

POSIX 标准不能保证sizeof(int) >= sizeof(ssize_t),反之亦然。通常ssize_t 大于int,但C99 中安全且可移植的选项是使用intmax_t 代替参数和返回值。

您拥有 wrt 的唯一保证。 intssize_t之间的关系是:

int 可以根据 ISO C 存储至少 [-2^15 ... 2^15-1] 范围内的值 ssize_t 可以根据 POSIX 存储至少 [-1 ... 2^15-1] 范围内的值(请参阅 _POSIX_SSIZE_MAX)。

(有趣的是,甚至不能保证ssize_t 可以存储其正数范围的负数。它不是带符号的size_t,而是带有错误值的“大小类型”。)

【讨论】:

ssize_t 实际上在 C 标准中根本没有指定。它是 POSIX 标准的一部分。 ssize_t 的链接只提到了最大尺寸,仅此而已,甚至没有提到签名。你能提供一个参考吗?谢谢。 我刚刚发现 int_fast64_t 存在于 C++11 中。我很想将它用作我的默认整数类型“最快的有符号整数类型,宽度分别至少为 8、16、32 和 64 位”en.cppreference.com/w/cpp/types/integer 就像@2501 所说的那样,您能否发布更多关于最小值的参考,因为您发布的参考并没有说明最小值。【参考方案2】:

以某种方式使用类型:

不要将signedunsigned 类型混合在一起,并且 不要截断较大类型的值,同时将它们存储在较小的类型中(溢出/下溢)

ssize_t 可能是 int 的别名,但它不是标准 C,可能是特定于环境的。

如果您的程序将在特定环境中运行,请检查是否sizeof(ssize_t) <= sizeof(int) 并使用int。否则,使用其他类型T,其中sizeof(T) 大于或等于sizeof(int)sizeof(ssize_t)

【讨论】:

ssize_t 不是 x86-64 系统上 int 的别名。 @larsmans:我已将其改写为“可能是 int 的别名”:) 我认为,出于实际原因,ssize_t 至少与指针大小相同,否则对最大写入大小会有不合理的限制。但我想不能保证指针的大小 >= int 的大小,还是有? @hyde:通常,ssize_tsize_t 的签名对应物,但 POSIX 甚至不保证这一点。 @larsmans 是的,我想可以为 32 位操作系统提出一个论点,使其具有 size_t 32 位,但 ssize_t 更宽,以避免仅限于写入/读取地址的一半空间...【参考方案3】:

您可以使用 int 或 long int 数据类型,但是 ssize_t 是一种系统数据类型,应该用于跨平台可移植性。基本类型(例如'int')在不同的实现中可以是不同的大小。通常发生的是系统类型(在本例中为 ssize_t)利用 C 的 typedef 功能,以便使用机器特定的数据类型大小,例如typedef signed ssize_t(这是 SUSv3 标准数据类型的一部分)。在实现任何类型的系统级编程时,最好尽可能使用系统数据类型。

有关更详细的说明,请参阅 Linux 编程接口 (Michael Kerrisk)

【讨论】:

以上是关于使用 ssize_t 与 int的主要内容,如果未能解决你的问题,请参考以下文章

应该使用 size_t 或 ssize_t [重复]

Web3.eth:溢出错误:Python int 太大而无法转换为 C ssize_t

我如何获得ssize_t以输出复制的字节? [处于保留状态]

ssize_t 重定义 不同的基类型

linux C中size_t和ssize_t的区别

使用read write 读写socket