由于历史上考虑到不同机器架构在处理不同位宽的整型时性能不同,所以当时的标准要求保证只要不小于某一宽度即可,具体多宽可由编译器自行决定,导致了在使用int或long时在不同机器上可能存在表现不同的情况。这样也大大降低了程序的稳定性和可移植性。C99标准中定义一组固定位宽的整型,在头文件stdint.h中,建议在编程中无特殊原因都使用这些固定位宽的整型,以保证程序在不同的机器构架下整型变量的大小依然相同。对应于C++11中相应的固定位宽的头文件是cstdin。所涉及到的类型主要有:
Name | Type | Range |
---|---|---|
int8_t | 1 byte signed | -128 to 127 |
uint8_t | 1 byte unsigned | 0 to 255 |
int16_t | 2 byte signed | -32,768 to 32,767 |
uint16_t | 2 byte unsigned | 0 to 65,535 |
int32_t | 4 byte signed | -2,147,483,648 to 2,147,483,647 |
uint32_t | 4 byte unsigned | 0 to 4,294,967,295 |
int64_t | 8 byte signed | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
uint64_t | 8 byte unsigned | 0 to 18,446,744,073,709,551,615 |
很好记,就是int或uint后面跟上所需要的位宽,然后后面再加个_t即可
查看了下linux下的头文件,发现有如下一些typedef:
1 |
|
用法就是直接包含头文件,然后定义使用即可:
1 |
|
C++中关于整型的使用建议是:
- 仅在整型变量的大小无关并且该变量不会变大时才使用int
- 通常情况下都应该考试使用固定宽度的整型,特别是当某个整型变量需要保证宽度的时候
- 只有当你有一个令人信服的理由时才使用无符号类型
当unsigned类的整型与signed整型混合使用时非常容易出问题(我自己写程序时遇到这个情况,debug好久才发现)如:
1 | void doSoming(unsigned int x) |
上面传递给函数中的-1有可能会变成非常大的数字。
所以编程中如果没有特别需要,最好避免使用unsigned类型。
一个小插曲
考虑练习下这些类型区别时,出现了一个让自己百思不得其解的问题,看如下代码:
1 |
|
我的第一反应是输出中i8的输出应该是8,结果却发现输出中第一行只有3个等号。很费解,gdb调试查看变量情况,gdb给的提示是i8 = 8 '\b'
,我依然没有反应过来哪里有问题(唉,这是有多久没有用char了)。然后开始查看头文件中对int8_t的定义,发现了上述头文件,原来这货就是个有符号的char,然后印象中char不就是可以用来存int吗,而且它俩在很多情况下是可以无损转换的,为什么输出不是8呢。这才开始查char的资料,突然想起来ASCII码的事,char在内存中确实是以整型存储,但存储的是ASCII码的整型,而8的ASCII码是’\b’(表示退格)。注意对于char来说,它只能存储一个(对于转义字符只算一个字符)使用单引号括起来的字符,将一个整数赋给它实际上发生了类型转换,char会保留该整数的低8位,存储为相应ASCII码的二进制。如:std::cout << int('\b');
将会输出整数十进制的8;std::cout << char(8);
将会输出一个退格(虽然看不见),因为十进制ASCII码8对应的是退格;std::cout << int('8');
将会输出56,因为字符’8’对应的ASCII码的十进制是56;std::cout << char('8');
将输出一个字符8,当然本身就是个字符,是否强制转换并无影响。
总之,代码要天天敲,基础知识要经常回顾,不然忘的太快了。