C++基本内置类型
基本内置类型
在C++提供的基本内置类型中包含了算术类型和void类型。而算术类型又分为布尔型,字符型,整型以及浮点型:
和很多“现代”语言不同,C++并没有规定其基本内置类型的具体大小(所占的bit数),标准只对以下两点提了要求:
- 标准虽然没有规定具体的大小,但规定了下限,即基本内置类型的最小位数。
- 标准规定了相关基本内置类型之间的大小关系,比如char\(\lt\)short\(\leq\)int\(\leq\)long\(\leq\)long long。
类型 | 含义 | 最小长度 | 备注 |
---|---|---|---|
bool | 布尔值 | NA | |
char | 字符型 | 8 bits | 大小等于一个字节 |
wchar_t | 宽字符型 | 16 bits | |
char16_t | unicode字符型 | 16 bits | 大小固定 |
char32_t | unicode字符型 | 32 bits | 大小固定 |
short | 短整型 | 16 bits | |
int | 整型 | 16 bits | |
long | 长整型 | 32 bits | |
long long | 超长整型 | 64 bits | C++11标准引入 |
float | 单精度浮点型 | 6位有效数字 | |
double | 双精度浮点型 | 10位有效数字 | |
long double | 扩展精度浮点型 | 10位有效数字 |
语言细节
- char的大小等于一个字节:
C++并没有byte类型,一般都是默认char类型占用一个字节。那标准里面到底有没有这么个规定呢,其实是有的,«C++ Primer»中提到过char类型的长度等于一个字节,并保证sizeof(char)
等于1。 - char不等于signed char:
C++标准中没有规定char类型是有符号还是无符号的,如果需要用char来做运算的话需要指定signed char
或者unsigned char
。当然最好用int8_t或者uint8_t来做小整数运算。 - float的精度一般比int小:
之前以为int值可以无损地赋值给float变量,但事实上一般float的实现精度是比int值要小的,要用浮点数存储int值还是得用double。 - 64位整型——long long:
C++11标准引入的long long类型最小位数为64,虽然之前C++98标准中有long类型,但long在大部分平台上都是32位的。当需要更大整数的运算的时候long long还是很有用的,顺便一提,long long的输出描述符为%lld
。 - 有符号数的
>>
不等于算术右移:
C++标准没有规定有符号数的右移操作是属于算术右移还是逻辑右移,所以«C++ Primer»中建议位操作还是先转换为无符号数再做。 - 位移操作
>>
和<<
的未定义行为:
位移操作对位移的bit数有要求,当超出被位移数类型的总位数时结果属于未定义的。 - 基本内置类型的“默认”类型提升:
对于char和short等小整型在做算术运算的时候会直接提升为int/unsigned类型。在作为不定参数(比如printf)的时候char和short等也会直接提升为int/unsigned类型,float类型则会直接提升为double类型,这也是为什么printf中输出short和int都是用%d
,float和double都是用%f
的原因。 - 字面值常量的类型:
对于十进制整型字面值常量,类型推导顺序为int->long->long long
;而对于八进制和十六进制整型字面值常量,类型推导顺序则为int->unsigned->long->unsigned long->long long->unsigned long long
。对于浮点型字面值常量,类型推导顺序为double->long double
。
对C++基本内置类型不定长的看法
有些人觉得C++基本内置类型不定长这一设定非常落后,对源码级别的移植性造成了很大的阻碍。但我却认为这恰恰是C++的优点,因为C++将决定基本内置类型长度的权力交给了编译器实现,这样编译器就能根据具体的硬件平台来选择处理效率最高的方案。
就像刚才提到的整型字面值默认为int类型,这样做的原因就是因为int类型的处理效率往往是最高的,但每种硬件平台都有它自己的“int”类型,如果规定死了int类型的长度,那这种高效的语义也就失效了。
其实C++规定的最小长度已经可以满足很多应用场景了,当业务场景确实需要某种定长的类型的时候还有<cstdint>
中定义的各种定长类型宏。这一点也符合C++语言的风格,那就是没有语言规定的最佳实践,将选择留给程序员自己。