【问题标题】:comparing off_t and ssize_t with other types将 off_t 和 ssize_t 与其他类型进行比较
【发布时间】:2015-10-09 17:20:20
【问题描述】:

我是 C 新手,最近遇到了一些不匹配的数据类型及其内存分配的问题。我正在编写一个非常简单的程序来计算使用 Linux 系统调用读取的文件的异或校验和。

我的问题是:在将 off_tssize_tlong 进行比较时,我是否需要担心不可预测的结果? >int?

例如:

long i;
for(i = 0; i < fileStat.st_size; i++)
{
    // do stuff 
}

还有:

ssize_t i;
for(i = 0; i < fileStat.st_size; i++)
{
    // do stuff
}

【问题讨论】:

    标签: c


    【解决方案1】:

    将具有相同符号但大小不同的类型与另一个作​​品进行比较,因为较小的类型扩展到较大的类型。比较不同签名的类型是有问题的,因为如果有符号类型不大于无符号类型并且有符号数为负数,则可能会得到错误的结果。最好首先确保带符号的数字不是负数:

    signed_t a;
    unsigned_t b;
    
    /* instead of */
    if (a < b)
        /* ... */
    
    /* use */
    if (a < 0 || a < b)
        /* ... */
    

    【讨论】:

    • 比较不同签名的类型是有问题的,因为如果两种类型的大小相同且带符号的数字为负数,您可能会得到错误的结果我不太明白这一行。可以举个例子吗?
    • @ameyCU 如果两种类型的大小相同,则在转换之前将有符号类型转换为无符号类型(参见 ISO 9899:2011§6.3.1.8)。如果有符号类型的对象是负数,则将其转换为正数,这可能会产生错误的结果。
    • signedness 你的意思是 sign 或 unsigned type 。我误解了类型是否已签名,但第一个是 +,第二个是 -
    • @ameyCU 是的。这就是为什么我写的是“具有相同符号的类型”,而不是“具有相同符号的值”。
    • 虽然 FUZxxi 的回答是正确的,但这些示例的真正解决方案是使用至少与您要比较的计数器类型一样宽的类型。否则,在具有 32 位指针、整数或长整数以及 64 位文件偏移的环境中,您的程序将因文件大小超过 2GiB 而中断。只需使用off_t i
    【解决方案2】:

    C 标准规定 long 类型足够大以表示常量 LONG_MAX,它必须至少为 2147483647 (231-1)。如果我们将此下限作为LONG_MAX 的值,那么它可能不够大。毕竟,它不到 2 GiB。

    ssize_t 不在 C 标准中,但在 POSIX 标准中定义。它必须足够大以表示常量SSIZE_MAX,它必须至少为 32767 (215-1)。也不要依赖这种类型。

    在我的机器上,longssize_t 都是 4 个字节。您可以使用sizeof 运算符自己验证大小。你可能会得到不同的结果。如果您希望您的程序具有可移植性,请不要依赖特定于实现的东西。

    最后,如果你真的不想使用那些 typedef,我推荐使用 unsigned long long 类型。它足够大,可以表示常量ULLONG_MAX,它必须至少为 18446744073709551615 (264-1)。

    另请参阅:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html

    【讨论】:

    • 我看不出这个答案有什么帮助。您指定的所有边界都是实际边界的下限。例如,在我的系统(amd64 Linux)上,ssize_tsigned long,比较 ssize_tunsigned long long 可能会导致问题。
    • @FUZxxl: Sigh... 关键是,您不能依赖任何整数类型来确定大小。在对程序中的类型进行任何假设之前,至少通过上述常量确认限制。另外,我举了一个这些限制的例子。 longssize_t 在我的机器上都是 4 个字节。不足以代表一个大文件的大小!
    • 注意:由于OP如何提出问题,可能存在一些误解。你是对的,你不应该将ssize_tunsigned long long 进行比较。我不是说别的。我的回答基于他给出的例子,尽管基本观点(不依赖于实施)是成立的。
    • 无论涉及的类型有多大,我的解决方案都能正常工作。转换为更大的类型并不能很好地工作,尤其是考虑到在当今的大多数平台上off_tsigned long long
    • @FUZxxl:让我们把事情弄清楚。转换为更大的类型很好,除非您正在从有符号类型转换为无符号类型,而前者为负数。然而,从较大的类型转换为较小的类型是有问题的,因为结果会绕过较小类型的限制。行为是特定于实现的,除非类型是无符号的,在这种情况下它是一个模运算:例如i % LLONG_MAX
    【解决方案3】:

    有关有符号和无符号整数(以及其他算术运算)之间比较的警告源于两个不同类型的操作数与运算符组合时发生的隐式转换。

    在 Gimpel 的 PC-Lint 工具附带的手册中有一个很好的章节。

    阅读可用的 C 标准文档,尤其是“整数提升”会很有帮助。

    例如http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf (C99) - 第 6.3.1 节“算术操作数”

    特别是“如果一个 int 可以表示原始类型的所有值,则将该值转换为 int;否则,将其转换为 unsigned int”

    因此,在这种情况下,“-1”将被转换为二进制全一 [依赖于实现] 作为无符号数 - 可能会给粗心的人带来令人惊讶的结果。例如,一个无符号整数除以整数“-1”将得到零。

    答案是在算术之前将无符号转换为有符号值。

    注意 sizeof() 返回一个无符号值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-20
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-31
      • 1970-01-01
      • 2019-05-28
      相关资源
      最近更新 更多