代码之家  ›  专栏  ›  技术社区  ›  MK.

64位上的int vs size\t

  •  16
  • MK.  · 技术社区  · 16 年前

    将代码从32位移植到64位。很多地方都有

    int len = strlen(pstr);
    

    size_t len = strlen(pstr);
    

    但是我刚刚意识到这是不安全的,因为size\u t是无符号的,并且它可以被代码当作有符号的(实际上我遇到了一个例子,它导致了一个问题,谢谢,单元测试!)。

    盲目地施展strlen return到(int)感觉脏兮兮的。或者不应该?

    6 回复  |  直到 16 年前
        1
  •  5
  •   Steve Jessop    16 年前

    作为妥协,你可以 ssize_t (如有)。如果不是,用 long long int_fast64_t , intmax_t 在POSIX中不是标准C或C++,但是如果您碰到的平台没有一个相同大小的签名类型 size_t

    投出 int 几乎是安全的(假设在64位平台上使用32位int,这似乎是合理的),因为字符串的长度不太可能超过2^31字节。转换为更大的有符号类型更安全。能够负担2^63字节内存的客户在业内被称为“一个好问题”;—)

    size_t ulen = strlen(pstr);
    if (ulen > SSIZE_MAX) abort(); // preferably trace, log, return error, etc.
    ssize_t len = (ssize_t) ulen;
    

    当然会有开销,但是如果您有1000个实例,那么它们不可能都是性能关键型的。如果有的话,你可以调查 len 签字其实很重要。如果没有,请切换到 大小\u t . 如果是这样的话,就重写或者冒险永远不要碰到这么大的东西。在32位平台上,如果 结果呈阴性 strlen 返回的值大于 INT_MAX

        2
  •  8
  •   mloskot    16 年前

    前段时间我在博客上发表了一篇关于这类问题的短文,简短的回答是:

    Always use proper C++ integer types

    在C++编程时,使用与特定上下文相关的适当整数类型是一个好主意。严格一点总会有回报的。忽略定义为特定于标准容器的整数类型的趋势并不少见,即size\u类型。它可用于标准容器的数量,如std::string或std::vector。这种无知很容易遭到报复。

    下面是一个错误使用类型来捕获std::string::find函数结果的简单示例。我很肯定很多人会认为这里的无符号int没有错。但是,实际上这只是一个错误。我在64位体系结构上运行Linux,当我按原样编译这个程序时,它可以正常工作。但是,当我替换行中的字符串时 1

    #include <iostream>
    #include <string>
    using namespace std;
    int main()
    {
      string s = "a:b:c"; // "abc" [1]
      char delim = ':';
      unsigned int pos = s.find(delim);
      if(string::npos != pos)
      {
        cout << delim << " found in " << s << endl;
      }
    }
    

    修复非常简单。只需将无符号int替换为std::string::size\u类型。如果编写这个程序的人注意使用正确的类型,这个问题就可以避免。更不用说这个程序可以直接移植。

    我见过很多问题,尤其是在前C程序员编写的代码中,这些程序员不喜欢使用C++类型系统强制和要求的严格口吻。上面的例子很小,但我相信它很好地说明了问题的根源。

    我推荐一篇精彩的文章 64-bit development 作者安德烈·卡尔波夫,你可以在那里找到更多关于这个主题的文章。

        3
  •  5
  •   pau.estalella    16 年前

    如果将编译器警告设置为最大级别,则可以很好地报告每个不正确的符号转换。在gcc中,“-Wall-Wextra”应该这样做。

    您还可以使用cppcheck之类的静态代码分析器来查看是否一切正常。

        4
  •  4
  •   caf    16 年前

    你可以用 ssize_t size_t ).

        5
  •  1
  •   osgx    16 年前

    在大多数情况下,您可以安全地处理未签名的站点。只有当无符号大小(或表达式中的中间结果)大于2^31(对于32位)或2^63(对于64位)时,它才会被视为负数。

    更新: 对不起,这种尺寸在建筑中是不安全的 while ( (size_t)t >=0 ) ssize_t .

        6
  •  1
  •   Johan    15 年前

    auto len = strlen(pstr);