编译型语言数据类型大小比较确定,可能有多种,但具体在特定平台特定编译器,大小一定是确定的。解释型语言或脚本处理数据类型更自由,默认看成“字符串”,在做数值运算自动转换。本文不过多讨论脚本类语言,它们不太关心这么多细节。
以如下标准的数据类型为例:
- char / short / int / long (long) / float / (long) double
sizeof
- C/ObjC/C++/C# 都提供sizeof运算符计算类型大小,尽管如此,编译型语言类型大小不是完全统一,甚至完全不是预期。
- C/ObjC/C++ sizeof既是关键字又是运算符,此运算符是编译器计算而非运行期计算。比较有意思的是,虽然是编译期可计算,它不能用于宏条件编译判断。
- Java没有sizeof运算符,因为它认为所有数据类型大小都是确定的,依然可以用<TYPE>.SIZE得到类型的比特数。
Integer.SIZE返回32. - Python用getsizeof获取变量大小,包括对象的其他内存开销,如下并不是等于4或者8.
sys.getsizeof(1) - 结构体的大小不一定等于所有成员大小之和,对齐影响最终的大小。
- 空类大小是0吗? C++不为0,为了避免不同对象在同一个地址。
char类型
- C/ObjC/C++ char类型为1字节,wchar_t一般为2字节。
- ObjC NSString字符串内部默认是UTF-16编码,一个字符是2字节。
- Java/C# char类型默认是Unicode字符,2字节。
C# char类型和ushort类型范围是一样的。 - Go有两种字符类型,byte是以往的1字节字符,rune代表4字节Unicode字符(相当于int32类型)。
- Swift用Character代表字符类型,Swift 5之前默认字符是UTF-16或ASCII码存储,即一个字符可能是1字节或2字节,Swift 5之后(包含)默认是UTF-8编码,根据字符所属范围长度不等。
short类型
- Fortran支持的整形之一,kind = 2代表2字节。
- C/C++不直接规定它的长度,要求不大于int类型,不小于char类型。具体实现一般为2字节。
- Java/C#中short固定为2字节。
int类型
- int类型代表计算机系统处理整形最自然的长度,一般和数据寄存器长度一样。
- 和short类型,Fortran kind=4即代表常规意义的标准的整形。
- 和short类似,C/ObjC/C++不直接规定它的长度,要求不大于long类型,不小于short类型。具体实现一般为4字节。
- 一般而言,16位系统int是2字节,32位系统int为4字节,而64位系统并不一定是8字节,因为有long的存在。
- Java/C#固定为4字节。
- Rust isize和usize类型长度取决于目标平台,i32和i64是固定大小。
- 仓颉Int32固定4字节,Int64固定8字节。
long类型
- C/C++规定long类型只要不小于int类型即可。
- Fortran kind=8代表8字节整形,有点类似于64位系统long的长度(一般而言)。
- 32位编译器,int和long一般都设置为4字节,另外Windows 16位环境下long也是4字节。
- 64位编译器,Linux平台long一般提升到8字节,int一般保持为4字节;Windows平台long和int保持为4字节,用long long表示8字节。这是由于Win64使用LLP64模型,Linux 64位使用LP64.
- 关于Windows 64位LLP64模型,可参考: Why did the Win64 team choose the LLP64 model?
- Java/C#固定为8字节。
long long类型
- 大部分编译器认为它不小于long类型即可,在64位系统一般为8字节。因为目前没有广泛使用128位系统,long long一般不会超过16字节。
float类型
- 一般float类型定义为4字节。
double类型
- 一般double类型定义为8字节。
long double类型
- 一般long double类型至少不小于double类型,不同编译器环境有差异。
- 不一定是16字节,可能保持和double类型一样为8字节,也可能是10字节。
- 32位的gcc比较特殊,long double长度为12字节。gcc也提供编译选项选择long double的长度,例如: -m128bit-long-double或-mlong-double-80等等.
- 带复数的complex long double类型一般是long double的2倍。
char *类型
- C/C++对char *类型的处理不能完全按指针,要根据上下文。
- sizeof("hello")返回5,而不是指针的大小4或者8.
- 数组变量的sizeof返回数组大小,而非数组的影子指针大小。
- 总结起来,当编译器能知道它的大小,就按那个大小,不能确定大小,按指针大小。