int 64bit上的size_t

问题描述:

将代码从32位移植到64位。很多地方有int 64bit上的size_t

int len = strlen(pstr); 

这些现在都产生警告,由于strlen()返回的size_t是64位和INT仍然是32位。所以,我一直在

size_t len = strlen(pstr); 

取代他们,但我才意识到,这是不是安全的,因为为size_t是无符号和代码的签署可以治疗(我居然遇到了一个情况就引起了问题,谢谢你,单元测试!)。

盲目投射strlen返回到(int)感觉脏。或者,也许它不应该?
所以问题是:有没有一个优雅的解决方案呢?我可能在代码库中有一千行代码,我无法手动检查它们中的每一个,测试覆盖率目前介于0.01和0.001%之间。

+1

你有没有在那里为签署本长度被视为一个例子吗? – kroimon 2010-03-25 21:31:51

+0

这个例子可能是沿着这样一条线的: 'len--;如果(len Tim 2013-06-19 18:02:24

作为折衷方案,您可以使用ssize_t(如果有)。使用long long,int_fast64_t,intmax_t,或者有一个平台移植头,可以为平台指定合适的类型,将它们假冒。 ssize_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签名是否真的很重要。如果没有,请切换到size_t。如果确实如此,重写或者冒险永远不会遇到一个荒谬巨大的对象。如果len由于strlen的返回值大于INT_MAX而导致结果为负,则原始代码几乎肯定会在32位平台上完成错误的操作。

+0

我同意cast到int几乎是安全的,但我不明白ssize_t有什么意义:它也是*安全的。它比int更安全,但仍然 - size_t可以比ssize_t更大。 – 2010-03-25 21:37:07

+0

@MK,'ssize_t'必须和'size_t'的大小相同 – osgx 2010-03-25 21:41:54

+2

@MK:我认为'ssize_t'的一般意图是在实践中,POSIX实现不会允许单个对象大于可用的地址空间。执行这个'malloc'很容易,尽管我不认为它是有保证的。有一个有符号大小的类型可以表示偏移量,这些偏移量可以是负值。 – 2010-03-25 21:43:36

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

更新: 对不起,size_t在while ((size_t)t >=0)等结构中不安全。所以正确的答案是使用ssize_t

+1

我的意思是这样的情况,我然后将len减少到一个负值。 while(len> 0) – 2010-03-25 21:36:08

+0

loop' while(len> 0)'应该在'len == 0'处停止,如循环 。 请向我们展示您的示例,单元测试发现的问题。 – osgx 2010-03-25 21:40:14

+2

Blah,对不起,我的意思是if(len = 0)做某事;” – 2010-03-25 21:43:48

将编译器警告设置为最高级别应该会为您提供有关每个不正确符号转换的良好报告。在gcc中,'-Wall -Wextra'应该这样做。

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

+0

和-wall将在签名的上下文中找到size_t正在使用的所有地方。你真的应该使用size_t – pm100 2010-03-25 21:40:36

您可以使用ssize_t(签署的变体size_t)。

前段时间我发布一个简短的说明关于这种在我的博客和简短的回答的问题是:

Always use proper C++ integer types

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

下面是一个错误地使用类型来捕获std :: string :: find函数结果的简单示例。我很确定很多人会认为这里的unsigned int没有问题。但是,实际上这只是一个错误。我在64位体系结构上运行Linux,当我编译该程序时,它按预期工作。然而,当我与ABC线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; 
    } 
} 

修复是非常简单的。只需将unsigned int替换为std :: string :: size_type即可。如果编写这个程序的人负责使用正确的类型,这个问题就可以避免。更不用说该程序可以直接移植了。

我见过这类问题的次数很多,特别是在前C程序员编写的代码中,他们不喜欢穿C++类型系统强制要求的严格的口吻。上面的例子是微不足道的,但我相信它很好地解决了问题的根源。

我推荐由Andrey Karpov撰写的精彩文章64-bit development,你可以在这里找到更多的内容。

+2

尽管我一般同意“使用正确的类型”,但是std :: some_container :: size_type在所有体面的实现中归结为size_t。据我所知,至少'std :: bitset :: size_type','std :: array :: size_type','std :: initializer_list'和'std :: allocator :: size_type'是typedefs for' size_t'。所以除非你使用疯狂的分配器或非常特殊的模板参数,'size_t'就足够了。 – rubenvb 2011-06-09 10:02:23

如果你的编译器支持的C++ 0x:

auto len = strlen(pstr);