将代码从32位移植到64位 . 有很多地方
int len = strlen(pstr);
这些都会产生警告,因为strlen()返回的是size_t,它是64位,而int仍然是32位 . 所以我一直在用它们取而代之
size_t len = strlen(pstr);
但我只是意识到这是不安全的,因为size_t是无符号的,它可以被视为代码签名(我实际上碰到了一个导致问题的情况,谢谢你,单元测试!) .
盲目地将strlen返回到(int)感觉很脏 . 或者也许它不应该?
所以问题是:这有一个优雅的解决方案吗?我可能在代码库中有一千行代码;我不能手动检查它们中的每一个,测试覆盖率目前介于0.01和0.001%之间 .
6 回答
如果您的编译器支持c 0x:
在大多数情况下,您可以安全地处理site_t签名 . 无符号size_t仅在它(或表达式中的中间结果)大于2 ^ 31(对于32位)或2 ^ 63对于64位时才被视为负 .
更新:抱歉,size_t在
while ( (size_t)t >=0 )
等结构中不安全 . 所以正确的答案是使用ssize_t
.作为妥协,您可以使用
ssize_t
(如果可用) . 如果没有,请使用long long
,int_fast64_t
,intmax_t
,或者使用平台移植标头,以便为平台指定合适的类型 .ssize_t
在POSIX中不是标准C或C,但是如果您曾经遇到过没有与size_t
相同大小的签名类型的平台,那么我同情 .对
int
的强制转换几乎是安全的(假设您的64位平台上有32位int,这似乎是合理的),因为字符串不可能超过2 ^ 31字节长 . 对更大的签名类型的强制转换甚至更安全 . 能够负担2 ^ 63字节内存的客户在业内已知为"a good problem to have" ;-)当然,你可以检查一下:
当然,所有这些都是性能至关重要的 . 对于那些(如果有的话),您可以开展工作来调查签署的
len
是否真正重要 . 如果没有,请切换到size_t
. 如果确实如此,重写或冒险从不会遇到一个荒谬的巨大对象 . 原始代码几乎肯定会在32位平台上做错了,如果len
由于strlen
返回大于INT_MAX
的值而为负 .前段时间我在博客上发布了关于此类问题的简短说明,简短的回答是:
Always use proper C++ integer types
答案很长:用C语言编程时,最好使用与特定上下文相关的正确整数类型 . 一点点的严格总是回报 . 看到忽略定义为特定于标准容器的整数类型(即size_type)的趋势并不罕见 . 它可用于标准容器的数量,如std :: string或std :: vector . 这种无知可能很容易报复 .
下面是一个错误使用类型的简单示例,用于捕获std :: string :: find函数的结果 . 我很确定很多人会认为unsigned int没有任何问题 . 但是,实际上这只是一个错误 . 我在64位架构上运行Linux,当我按原样编译该程序时,它按预期工作 . 但是,当我用abc替换行1中的字符串时,它仍然可以工作但不像预期的那样:-)
修复非常简单 . 只需用std :: string :: size_type替换unsigned int . 如果编写此程序的人负责使用正确的类型,则可以避免这个问题 . 更不用说该计划将立即便携 .
我已经很多次见过这种问题了,特别是在前C程序员编写的代码中,他们不喜欢穿C类系统强制执行和要求的严格的枪口 . 上面的例子是一个微不足道的例子,但我相信它很好地解决了问题的根源 .
我推荐由Andrey Karpov撰写的精彩文章64-bit development,你可以在这里找到更多关于这个主题的文章 .
将编译器警告设置为最大级别可以为您提供每个不正确的符号转换的良好报告 . 在gcc中,'-Wall -Wextra'应该这样做 .
您还可以使用像cppcheck这样的静态代码分析器来查看是否一切正常 .
您可以使用
ssize_t
(size_t
的签名变体) .