为什么会有 ”size_t为何要存在” 的疑问?
许多C/C++文件中都会出现类型size_t
,比如在bitcoin源码中,有这样的一个函数:
size_t strnlen( const char *start, size_t max_len)
{
const char *end = (const char *)memchr(start, '\0', max_len);
//memchr函数从start开始寻找第一个出现字符'\0'的位置并返回
return end ? (size_t)(end - start) : max_len;
//const char的长度吧,为啥要这样写,为什么要单独写一个文件啊,NOTE
}
该函数完成了返回const char*
类型start
代表的串的长度,返回值被设置为size_t
类型。这是size_t
经常被使用的一个场景“数组可能的长度。
另一个使用场景就是函数memcpy
(其实本质上是一样的,都是表示内存中数据的多少)。memcpy
的原型void* memcpy(void*to,const void*from,size_t n)
。需要复制的字节数被设置为size_t
类型,这是数据块的大小。
于是,会给人一种感觉,这种工作int
也可以完成,如果说需要排除负数,unsigned int
也可以完成。为什么要多此一举引入size_t
呢?
另外,为何要表示内存中所有的数据呢?为什么不是硬盘?
这就是操作系统范畴的东西了。程序所使用的数据,一定是先由OS把数据搬/swap到内存,再根据内存地址去访问。至于怎么从硬盘中找到,就是另一件事情了,它被叫做”缺页中断“。
为什么需要size_t?
首先声明size_t
的功能,它需要保证在程序运行中可以表示所有内存地址。size_t
根据具体机器的体系结构,将有不同的值。比如,32位系统,内存最大是$2^{32} bytes=4G$。那么size_t
就需要至少4个字节(32bits)来表示所有地址。
即使是这样,unsigned int
不是也是4个字节吗?
有些系统是。
为了保证在一些有者特殊体系结构的机器上正确运行,使用unsigned int
来表示数据块大小可能是一个不好的主意。比如,一个机器支持16bit的unsigned int
,但他是一个32位系统,使用unsigned int
代替size_t
显然并不是一个好主意。假如出现一个特别大的数组,可能无法表示出这个数组所有的元素,显而易见。
那么,是否可以使用unsigned long
来代替呢?毕竟,long一定需要至少32bits,那么,对于那些只有16位的平台呢,这些平台往往使用两个16bits的字来对应一个long
,在对long
进行操作时,一定需要至少两条操作指令。而在这个系统中,并不需要32bits的地址,因为他只有16位。
要为了兼容而舍弃性能吗?显然有更好的解决方案。那就是根据地址总线个数来决定一个类型的大小,既不会无法表示一些数据,又不会使一些机器效率折损。这个类型就是size_t
。
size_t
的存在使得程序有更好的可移植性,显而易见,程序员不需要为了一个新机器而在unsigned int
和unsigned char
等等类型之间改来改去。
size_t的使用
正如上述,size_t
可以表示内存中的所有数据,因为它刚好能够表示内存中所有的地址。
根据定义,size_t
是关键字sizeof
运算得到的结果的类型。因此,使用sizeof
得到的结果应该声明为size_t
:
size_t n=sizeof(int)
另外,就是第一小节所述的,表示数组大小、数据块大小等等(实际上也是数据块的大小)。
使用size_t
的时候,记得包括它的定义所在头文件,比如<stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>,<wchar.h>
中的任意一个。
![](/qrcode.jpg)