size_t是什么?为什么要使用它?
首先,我们给出size_t的定义:
size_t的全称是size type,即“记录大小的数据类型”,是sizeof运算结果的类型,一个unsigned整型。
以防万一,sizeof(chr)返回的是变量或类型在内存中占用的字节数。
size_t 被用在哪里?
c库中的许多函数会使用size_t,请看如下函数的定义:
void *malloc(size_t n);
void *memcpy(void *si, void const *s2, size_t n);
size_t strlen(char const *s);
没错,strlen返回的并不是int,而是一个size_t。
但为什么不直接使用int,而是size_t?
因为size_t可以提高代码的可移植性与可读性,下面我们会解释原因。
为什么是size_t?
首先,数据的大小不可能是负数,为了能表示更大的范围,储存数据大小的类型应该是unsinged的。
为什么不能用unsigned int?
在不同的系统架构中,整型和指针占用的字节数是不同的。
有些时候整型和指针的字节和指针的字节数相同(比如IP16),指针传回的数据范围与int也是相同的,在这里使用unsinged int并不会产生问题。
但在另一些架构里(比如I16LP32),占32字节的指针有可能传回比int更长的数据,仅靠unsinged int就无法处理这么大的数据了。
I16、I16LP32描述的是不同平台下c语言数据的实现,用大写字母代表数据类型,数字代表该类型所占用的字节数。
例如I16LP32代表的是:支持16位int,32位long与指针。
I L LL P依次为int, long, long long, 指针
为什么不用unsigned long?
如果unsigned int不够大,那全部替换成unsigned long总够用了吧?
使用unsigned long确实能保证函数的参数处理32位指针传回的数据,但在IP16L32平台中,long通常是由一对16位的块来实现的,这使得移动long时需要执行两条机械指令(在这样的平台上,大部分对32位数据的操作都需要两条机器指令),在这种平台上,你的代码效率会大大降低。
不仅如此,即使unsigned long也可能不足以处理传入的数据,也许我们甚至还要改成unsigned long long...
使用size_t
此时,我们可以发现int和long的问题出现在移植上:要么不能正确地在不同架构中运行,要么在一些架构中效率降低,若要进行完美的移植,就要为不同架构替换不同的数据类型(这真是太恐怖了)。
size_t则不会产生这些问题,它代表了对应数据在架构中占用的字节数,也就是说,在IP16架构中,它可以处理16位的数据,在I16LP32架构中,不需要对代码作出更改,这个参数就能处理32位的数据。同时,只要看到size_t我们就能知道它代表的是一个字节大小或一个数组的索引,这也是为什么它能提高代码的可读性。