零.位(Bit),字节(Byte),字(Word):
位/字节/字是描述计算机数据单元或存储单元的术语
最小的存储单元是位,可以存储1个2进制数(即0或1),是计算机内存的基本构建块
字节是常用的计算机存储单位;1字节等于8位,这是字节的标定义(但C语言对此有不同的定义)
8位字节可以表示256个状态,如0~255的整数或256个不同的字符
字是设计计算机时给定的自然存储单位;计算机的字长越大,数据转移越快,允许的内存访问也更多
对于8位的微型计算机,1个字长只有8位,之后,个人计算机字长增长到16位/32位,直到目前的64位
一.整型
1.整型占用的内存大小及表示范围:
一般而言,1个int类型的值占用1个机器字长,如在32位计算机上占用4B,在64位计算机上占用8B
在早期的16位IBM PC兼容机上int占用2B,表示范围是-32768~32767
因此ISO C规定int最小的表示范围是-32768~32767
现在,一般情况如下:
long long:64位 long:32位 int:16位或32位 short:16位
C标准对基本数据类型只规定了允许的最小大小:
short与int:[-32768,32767] long:[-2147483648,2147483647]
unsigned short与unsigned int:[0,65535] unsigned long:[0,4294967295]
long long:[-9223372036854775808,9223372036854775807]
unsigned long long:[0,18446744073709551615]
由于通常用不到负值,优先使用unsigned类型以存储更大的值
在long和int均占用4B的机器上,在需要4B时使用long而非int,以保证移植到16位机器上仍可运行
类似地,在需要8B时使用long long
某些寄存器是16位的,使用short可以加快运算速度
2.整型常量的后缀:
l/L:long,如32435L,0x3278L(16进制)
ll/LL:long long,如43818933LL,0382938LL(8进制)
ull/ULL/Ull/LLU/LLu/uLL/llu/llU:unsigned long long,如1062989755ULL
3.输出时整型的类型错误:
unsigned int a=3000000000u;//该常量超出了int的范围,不加u会警告并自动转换为unsigned
printf("%u,%d\n",a,a);//结果:3000000000,-1294967296
//因为二者在内存中的2进制表示完全相同,显示的结果只取决于以什么格式输出
long b=65537;
printf("%ld,%hd\n",b,b);//结果:65537,1
//65537写成2进制格式是00000000000000010000000000000001
//通过%hd输出时会被截断,只显示后16位就成了1
4.可移植类型:
C语言的某些类型在不同系统中功能不同,为此C99新増了头文件stdint.h和inttypes.h,以确保C语言的类型在各系统中功能相同
C语言为现有类型创建了更多类型名,这些新的类型名被定义在stdint.h中:
①如int32_t表示32位的有符号int,在使用32位int的系统中,头文件会把int32_t作为int的别名
而在int为16位,long为32位的系统中,头文件会把int32_t作为long的别名
以上是精确宽度整数类型(Exact-Width Integer Type)的示例,int32_t表示int的宽度是32位
但是,计算机的底层系统可能不支持,因此,精确宽度整数类型是可选项
②如果系统不支持精确宽度整数类型,C99/C11还提供了第2类别名集合:
一些类型名保证所表示的类型是至少有指定宽度的最小整数类型,称为最小宽度类型(Minimum-Width Type)
如int_1east8_t是可容纳8位有符号整数值的类型中宽度最小的那个的别名
如果某系统的最小整数类型是16位,可能不会定义int8_t类型
但在该系统中仍可使用int_least8_t类型,但可能把该类型实现为16位的整数类型
③一些程序员更关心速度而非空间,为此c99/C11定义了1组可使计算达到最快的类型集合,称为最快最小宽度美型(Fastest Minimum-Width Type)
如int_fast8_t被定义为系统中对8位有符号整数值而言运算最快的整数类型的别名
④另外,有些时候需要用到系统的最大整数类型
为此,C99定义了最大的有符号整数类型intmax_t,其可存储任何有效的有符号整数值
类似地,uintmax_t表示最大的无符号整数类型,其可存储任何有效的无符号整数类型值
这些类型可能比unsigned long long更大,因为C编译器除实现标准规定的类型外,还可以利用C语言实现其他类型
例如,一些编译器在标准引入1ong 1ong之前,已提前实现了该类型
⑤C99/C11不仅提供可移植的类型名,还提供相应的输入和输出
如printf()打印特定类型时要求与相应的转换说明匹配,如果要打印int_32t类型的值,有些定义使用d,而有些定义使用1d
C标准针对这一情况,提供了一些字符串宏来显示可移植类型
如antitypes.h中定义了PRId32字符串宏,代表打印32位有符号整数值的合适转换说明(如d或1d)
二.字符类型
1.C语言将字符常量视为int而非char:
char grade=65;//注意仅在使用ASCII码的系统上这么做才正确
printf("%c\n",grade);//65是A对应的ASCII码,故值是A
//在int占用4B,char占用1B的ASCII系统中:
char grade='FATE';
//字符常量'FATE'把4个1B的ASCII码字符存储在1个4B的存储单元中(因为字符常量被视为int)
//赋值给字符变量grade时只有最后1B有效,故grade的值是E
printf("%c,%d\n",grade,grade);//结果:E,69
printf("%d\n",'FATE');//结果:1178686533
//警告:
//[Warning] multi-character character constant [-Wmultichar]
//[Warning] overflow in implicit constant conversion [-Woverflow]
//[Warning] multi-character character constant [-Wmultichar]
2.非输出控制符可以用ASCII码代替:
//有些编译器不能识别某些非输出控制符,这时可以用相应的ASCII码代替
char m='\7';//对应\a
//非输出控制符的ASCII码也可以嵌入到字符串中:
printf("AAA\7BBB\n");//结果:AAABBB//并发出1声警报
注意:直接使用非输出控制符(如'\f')的可移植性比使用ASCII码要高(对应为'\14')
3.char的符号:
有些编译器中char的范围是-128~127,另一些中是0~255
也可以直接使用signed char表示有符号的char(即范围为-128~127)
使用unsigned char表示无符号的char(即范围为0~255)
这在用char处理小整数时很有用;如果char只处理字符,无需指定是否有符号
三.浮点型
1.浮点型的表示范围与精度:
C标准规定:
①float必须至少能表示6位有效数字(非小数点后6位有效数字),且取值范围至少是e-37~e37
通常占用4B,其中1B用于表示指数的值和符号,3B用于表示小数部分(也称尾数/有效数)的值和符号
②double必须至少能表示10位有效数字,最小取值范围和float相同
通常占用8B,部分系统将多出来的4B全部分配给小数部分,部分系统会分配一些位给指数部分
③long double的精度应至少和double相同
2.16进制浮点型常量:
C99增加了这种新的浮点型常量格式(注意:并非所有编译器都支持):
在16进制数前加0x或0X前缀,用p/P代替e/E,用2的幂代替10的幂(即p计数法)
如0xa.1fp10表示(10+1/16+15/256)*(2^10)
3.上溢(Overflow),下溢(Underflow),NaN:
当数字过大,超过当前类型能表达的范围时,就会发生上溢,这种行为在过去是未定义的
但现在C语言规定,在这种情况下的值为inf或infinity或表示无穷大的其他值,如:
printf("%f\n",1.8e308);//结果:1.#INF00
//警告:[Warning] floating constant exceeds range of 'double' [-Woverflow]
如果某个数的指数已经是最小值,而尾数部分需要用尾数部分的全部可用位才能精确表示
现在对其除以2,由于指数已经最小,计算机只好把尾数部分的位右移并丢弃最后1个二进制数
以10进制为例,把1个有4位有效数字的数,如0.1234E-10除以10,得到的结果是0.0123E-10
虽然得到了结果,但在计算过程中却损失了原本最后1个有效位上的数字,这种情況叫作下溢
C语言把损失了类型全精度的浮点值称为低于正常的(Subnormal)浮点值
如果除以1个非常大的值,会导致所有的位都变为0
现在,C库提供了用于检查计算是否会产生低于正常的浮点值的函数
另1个特殊的浮点值是NaN(Not a Number),表示未定义的值或非数值的值
如给asin()传入大于1的参数,函数将返回NaN,printf()可将其显示为nan或NaN或其他类似的值
四.复数和虚数类型
C99/C11都支持复数和虚数类型,但一般作为可选项
复数类型:float _Complex,double _Complex,long double _Complex
虚数类型:float _Imaginary,double _Imaginary,long double _Imaginary
如果include了complex.h头文件:
①可以用complex代替_Complex,imaginary代替_Imaginary
②可以用I代替sqrt(-1)(注意:不能用i代替)
不直接使用complex和imaginary作为关键字是为了避免之前以此为标识符的代码失效
如很多之前的代码使用struct complex来定义1个结构体以表示复数或心理状况