Last Updated: 2023-12-12 04:52:35 Tuesday
-- TOC --
size_t类型与具体CPU架构有关,它所覆盖的范围与进程虚拟内存空间的范围一致,sizeof操作符返回值的类型就是size_t。ssize_t就是singed size_t。
_t
这个后缀,一般都指type,在C语言中,就是用typedef定义出来的类型,多出现在标准库的定义中。因此,不建议自己定义的类型也是用_t
这个后缀,可能会造成冲突。
简单地说,size_t类型(size type的联合简写体)就是一个unsigned整数,至于是unsigned int还是unsigned long等,就要看平台了,即CPU。
32位CPU对应unsigned int的size_t,64位CPU对应unsigned long的size_t。
size_t类型来自C语言标准头文件stdio.h
,只要include此头文件,就可以直接在代码使用size_t。
早期的C语言(由Brian Kernighan 和 Dennis Ritchie 在The C Programming Language书中所写,Prentice-Hall, 1978)并没有提供size_t类型,C标准委员会为了解决代码移植性问题,将size_t引入。因此,最经典的C89就有这个类型,C标准库中很多函数的参数类型,都是它,比如malloc(size_t n)
。
为什么有size_t这个类型?它的作用是什么?
C标准库中提供size_t类型的目的,是为了让C代码具有更好的可移植性和执行效率。
size type中的size,我理解是指进程的虚拟地址空间,比如在32位系统中,进程的寻址空间是4G,正好对应4字节的unsigned int类型。假设进程有一个超大的字符数组,大小就是4G(实际上不可能),此时操作这个数组的index,就应该被定义为4字节的unsigned int类型。但有些系统是16位的,平台提供的int是2个字节,但指针大小还是4字节。而现在主流CPU都是64位的,但int还是4字节。如果代码对于数组index的定义一直使用unsigned int,在前述16位系统上,就会无法访问超过65535大小的数组;在前述64位系统上,也会出现无法访问长度超过4G的数组。
32位系统中,进程的虚拟地址空间,一般是低2G,不可能用满4G,OS kernel还要占一部分。64位系统中,就很大了,128T。
如果16位系统,指针也是16位的,如果代码将index定义为unsigned long,4字节,虽然可以覆盖全部内存地址,但是执行效率上又会受到影响。(16位的CPU寄存器操作32位数据)
size_t类型的出现,就解决了以上说明的代码可移植性和执行效率的问题。
由于size_t类型是标准库中定义的,它的大小一定对应了CPU的寄存器位数,就不会再出现无法访问的地址段,代码也具有了更好的可移植性。size_t始终对应平台指针大小,既保证了覆盖所有地址,也保证了效率。
因此,数组index之类的数据结构,都可以考虑使用size_t类型来申明其大小,代码的可读性也更好。一看到size_t,就知道这个类型的大小由编译平台决定,可以保证代码可移植性和执行效率。
stackoverflow上的一段文字:
- Because unsigned int is not the only unsigned integer type. size_t could be any of unsigned char, unsigned short, unsigned int, unsigned long or unsigned long long, depending on the implementation.
- On one system, it might make sense to use unsigned int to represent sizes; on another, it might make more sense to use unsigned long or unsigned long long. (size_t is unlikely to be either unsigned char or unsigned short, but that's permitted).
- The purpose of size_t is to relieve the programmer from having to worry about which of the predefined types is used to represent sizes.
- Code that assumes sizeof yields an unsigned int would not be portable. Code that assumes it yields a size_t is more likely to be portable.
There are 5 standard unsigned integer types in C:
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
with various requirements for their sizes and ranges (briefly, each type's range is a subset of the next type's range, but some of them may have the same range).
size_t 在 VC++2010 的 crtdefs.h 文件中的定义如下所示:
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif
#define _SIZE_T_DEFINED
#endif
In short, ssize_t is the same as size_t, but is a signed type - read ssize_t as
signed size_t
. ssize_t is able to represent the number-1
, which is returned by several system calls and library functions as a way to indicate error. For example, the read and write system calls:
#include <sys/types.h>
#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbyte);
ssize_t write(int fildes, const void *buf, size_t nbyte);
虽然我们用size_t表示size,但是实际上可能出现的最大size,远小于size_t的最大值,这就给sszie_t类型提供了空间来同时表达真实的size和错误时的-1。比如C++中的string::npos,它的类型虽然是size_t,但其值为string::npos == (size_t)-1
。
本文链接:https://cs.pynote.net/sf/c/202111196/
-- EOF --
-- MORE --