第三章 数据和C
int
unsigned int
long
unsigned long
long long
unsigned long long
float
double
long double
(4) 布尔类型 _Bool >>
其取值范围依计算机系统而异
储存一个int要占用一个机器字长
(1) ISO C规定int的取值范围最小为-32768~32767(16位) >>
(2) long long int或long long(C99标准加入) >>
在C90标准中,添加了unsigned long int或unsigned long和unsigned int或unsigned short类型。 C99标准又添加了unsigned long long int或unsigned long long。
(3) C语言把不含小数点和指数的数作为整数 >>
C语言把大多数整型常量视为int类型,但是非常大的整数除外
使用不同的进制数是为了方便,不会影响数被储存的方式
因为计算机内部都以二进制进行编码
i) 整数可以表示为十进制、八进制或十六进制。0前缀表示八进制数,0x 或0X前缀表示十六进制数 >>
b) C语言只规定了short占用的存储空间不能多于int, long占用的存储空间不能少于int。这样规定是为了适应不同的机器 >>
(1) 依计算机的自然字长而定 >>
个人计算机上最常见的设置是,long long占64位,long占32位, short占16位,int占16位或32位(依计算机的自然字长而定)。原则上,这4 种类型代表4种不同的大小,但是在实际使用中,有些类型之间通常有重叠。
i) int类型的宽度要么和long类型相同,要么和short类型相同 >>
obsidian://open?vault=Obsidian&file=Courses%2FC%20primer%20plus%2F%E7%AC%AC%E4%B8%89%E7%AB%A0%20%E6%95%B0%E6%8D%AE%E5%92%8CC%2Fint%E5%8D%A0%E5%87%A0%E4%BD%8D%EF%BC%9F
i) 类型自动调整int->long int->unsigned long->long long >>
如果使用1000000这样的大数字,超出了int类型能表示的范围,编译器会将其视为long int类型(假设这种类型可以表示该数字)。如果数字超出long可表示的最大值,编译器则将其视为unsigned long类型。如果还不够大,编译器则将其视为long long或unsigned long long类型
暂时可以理解为,常量在申请之后,变量名指向的是在常量存储区中的一个int类型自动推断
long常量和long long 常量
#todo
ii) 有些情况下,需要编译器以long类型储存一个小数字 >>
可以在值的末尾加上l(小写的L)或L后缀。使用L后缀更好,因为l看上去和数字1很像
类似地,在支持long long类型的系统中,也可以使用ll或LL后缀来表示long long类型的值,如3LL。另外,u或U后缀表示unsigned long long,如5ull、10LLU、6LLU或9Ull
后缀并没有什么实际的作用但是能够标识
(3) 如果在long类型和int类型占用空间相同的机器上编写代码,当确实需要32位的整数时,应使用long类型而不是int类型,以便把程序移植到16位机后仍然可以正常工作。 >>
(4) 使用short类型的另一个原因是,计算机中某些组件使用的硬件寄存器是16位 >>
(5) 数据溢出 >>
unsigned int 类型的变量溢出会从 0开始
C 标准并未定义有符号类型的溢出规则
c) 这是因为在给函数传递参数时,C编译器把short类型的值自动转换成int类型的值 >>
int类型被认为是计算机处理整数类型时最高效的类型。因此,在short和int类型的大小不同的计算机中,用int类型的参数传递速度更快
(1) 使用h修饰符可以显示较大整数被截断成 short 类型值的情况 >>
第 3 行输出就演示了这种情况。把 65537 以二进制格式写成一个 32 位数是00000000000000010000000000000001。使用%hd,printf()只会查看后 16 位,所以显示的值是 1。与此类似,输出的最后一行先显示了verybig的完整值,然后由于使用了%ld,printf()只显示了储存在后32位的值。
d) C99 新增了两个头文件stdint.h和inttypes.h,以确保C语言的类型在各系统中的功能相同 >>
(1) 在使用32位int的系统中,头文件会把int32_t作为int的别名。不同的系统也可以定义相同的类型名 >>
(2) 上面讨论的类型别名是精确宽度整数类型(exact-width integer type)的示例。int32_t表示整数类型的宽度正好是32位。但是,计算机的底层系统可能不支持。因此,精确宽度整数类型是可选项 >>
i) 如果系统不支持精确宽度整数类型怎么办?C99和C11提供了第2类别名集合。一些类型名保证所表示的类型一定是至少有指定宽度的最小整数类型。这组类型集合被称为最小宽度类型(minimum width type)。 >>
(3) 一些程序员更关心速度而非空间。为此,C99和C11定义了一组可使计算达到最快的类型集合。这组类型集合被称为最快最小宽度类型(fastst minimum width type)。例如,int_fast8_t被定义为系统中对8位有符号值而言运算最快的整数类型的别名。 >>
i) 有些程序员需要系统的最大整数类型。为此,C99定义了最大的有符号整数类型intmax_t,可储存任何有效的有符号整数值。类似地, unitmax_t表示最大的无符号整数类型。 >>
(4) C99 和 C11 不仅提供可移植的类型名,还提供相应的输入和输出 >>
(5) 问题-2 >>
3.4.5 可移植类型:stdint.h和inttypes.h 这两个库要看一下
#todo
a) 因为char类型实际上储存的是整数而不是字符。 计算机使用数字编码来处理字符,即用特定的整数表示特定的字符 >>
所以也可使用数字代码值来赋值
(1) char类型也可以表示较小的整数 >>
(2) 探究Byte的定义 >>
C语言把1字节定义为char类型占用的位(bit)数,因此无论是16位还是32位系统,都可以使用char类型
obsidian://open?vault=Obsidian&file=Courses%2FC%20primer%20plus%2F%E7%AC%AC%E4%B8%89%E7%AB%A0%20%E6%95%B0%E6%8D%AE%E5%92%8CC%2Fint%E5%8D%A0%E5%87%A0%E4%BD%8D%EF%BC%9F
但是如果要表示基本字符集,也可以是16位或更大
更长的字符需要使用宽字符wchar_t=L“字”
(3) 有些C编译器把char实现为有符号类型,这意味着char可表示的范围是-128~127。而有些C编译器把char实现为无符号类型,那么char可表示的范围是0~255。请查阅相应的编译器手册,确定正在使用的编译器如何实现char类型。或者,可以查阅limits.h头文件 >>
i) 无论编译器默认char是什么类型,signed char表示有符号类型,而unsigned char表示无符号类型。这在用char类型处理小整数时很有用。如果只用char处理字符,那么char前面无需使用任何修饰符。 >>
#universal
(1) 标准ASCII码 >>
标准ASCII码的范围是0~127,只需7位二进制数即可表示。通常,char 类型被定义为8位的存储单元,因此容纳标准ASCII码绰绰有余。许多其他系统(如IMB PC和苹果Macs)还提供扩展ASCII码,也在8位的表示范围之内。一般而言,C语言会保证char类型足够大,以储存系统(实现C语言的系统)的基本字符集
(2) 商用的统一码(Unicode) >>
商用的统一码(Unicode)创建了一个能表示世界范围内多种字符集的系统
i) 国际标准化组织(ISO)和国际电工技术委员会(IEC)为字符集开发了ISO/IEC 10646标准。统一码标准也与ISO/IEC 10646标准兼容。 >>
c) 在C语言中,用单引号括起来的单个字符被称为字符常量(character constant)。编译器一发现'A',就会将其转换成相应的代码值。单引号必不可少。 >>
字符串作为常量,存储在静态区,直到程序结束才会被释放。 意味着 1 在C编译器中有一个基础的对应码表,把数字映射为字符,在字符串生成的时候把连续空间的整数放在静态存储区 2 当字符串作为一个常量定义的时候,如*c="hello world",这样他会在静态存储区申请相应的Bytes的内存,
obsidian://open?vault=Obsidian&file=Courses%2FC%20primer%20plus%2F%E7%AC%AC%E4%B8%89%E7%AB%A0%20%E6%95%B0%E6%8D%AE%E5%92%8CC%2F%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F%E5%AD%98%E5%82%A8
a) C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是10-37~10+37。 32位4Byte >>
(1) 浮点型常量的基本形式是:有符号的数字(包括小数点),后面紧跟e或E,最后是一个有符号数表示10的指数 >>
-1.56E+12
e后面的数字代表10的指数
b) double类型和float类型的最小取值范围相同,但double至少必须能表示10位有效数字 64位8Byte >>
(1) double占用64位而不是32位。一些系统将多出的 32 位全部用来表示非指数部分,这不仅增加了有效数字的位数(即提高了精度),而且还减少了舍入误差 >>
无论哪种方法,double类型的值至少有13 位有效数字,超过了标准的最低位数规定
C只保证long double类型至少与double类型的精度相同
96位12Byte
d) 正号可以省略。可以没有小数点(如,2E5)或指数部分(如, 19.28) 但是不能同时省略两者。 可以省略小数部分(如,3.E16)或整数部分(如,.45E-6) 但是不能同时省略两者。 >>
示例
(1) 不要在浮点型常量中间加空格 >>
e) 默认double类型 >>
默认double类型
some = 4.0 * 2.0;
(1) 4.0和2.0被储存为64位的double类型,使用双精度进行乘法运算,然后将乘积截断成float类型的宽度 >>
精度更高,但是会减慢程序的运行速度
在浮点数后面加上f或F后缀可覆盖默认设置,编译器会将浮点型常量看作float类型
f) 还有另一个特殊的浮点值NaN >>
printf()函数可将其显示为nan、NaN或其他类似的内容
(1) ,给asin() 函数传递一个值,该函数将返回一个角度,该角度的正弦就是传入函数的值。但是正弦值不能大于1,因此,如果传入的参数大于1,该函数的行为是未定义的。在这种情况下,该函数将返回NaN值 >>
g) C99 标准添加了一种新的浮点型常量格式——用十六进制表示浮点型常量,即在十六进制数前加上十六进制前缀(0x或0X),用p和P分别代替e和E,用2的幂代替10的幂(即,p计数法) >>
(2) 问题-3 >>
给那些未在函数原型中显式说明参数类型的函数(如,printf()) 传递参数时,C编译器会把float类型的值自动转换成double类型。程序清单3.7演示了这些特性。
这个怎么理解?程序中没有看到哪里体现? #todo
电子和电气工程师协会(IEEE)为浮点数计算和表示法开发了一套标准。现在,许多硬件浮点单元都采用该标准。2011年,该标准被ISO/IEC/IEEE 60559:2011标准收录。该标准作为C99和C11的可选项, 符合硬件要求的平台可开启。floaterr.c程序的第3个输出示例即是支持该浮点标准的系统显示的结果
(1) 上溢(overflow) >>
过去是未定义的,不过现在C语言规定,在这种情况下会给toobig赋一个表示无穷大的特定值,而且printf()显示该值为inf或infinity(或者具有无穷含义的其他内容)
(2) 下溢(underflow) >>
虽然得到了结果,但是在计算过程中却损失了原末尾有效位上的数字。这种情况叫作下溢(underflow)
以十进制为例,把一个有4位有效数字的数(如,0.1234E-10)除以10,得到的结果是0.0123E-10
如果除以一个非常大的值,会导致所有的位都为0
i) C库已提供了用于检查计算是否会产生低于正常值的函数 >>
float给定一个数,加上1,再减去原来给定的数
计算机缺少足够的小数位来完成正确的运算
a) C99标准添加了_Bool类型,用于表示布尔值,即逻辑值true和false。因为C语言用值1表示true,值0表示false,所以_Bool类型实际上也是一种整数类型。但原则上它仅占用1位存储空间,因为对0和1而言,1位的存储空间足够了 >>
a) C99 标准支持复数类型和虚数类型,但是有所保留 >>
一些独立实现,如嵌入式处理器的实现,就不需要使用复数和虚数(VCR芯片就不需要复数)。一般而言,虚数类型都是可选项。C11标准把整个复数软件包都作为可选项
b) C语言有3种复数类型 >>
(1) 虚数类型是可选的类型。复数的实部和虚部类型都基于实浮点类型来构成: >>
float _Complex double _Complex long double _Complex float _Imaginary double _Imaginary long long _Imaginary
c) 如果包含complex.h头文件 便可用complex代替_Complex 用imaginary 代替_Imaginary 还可以用I代替-1的平方根 >>
(1) 为何 C 标准不直接用 complex 作为关键字来代替_Complex >>
因为标准委员会考虑到,如果使用新的关键字,会导致以该关键字作为标识符的现有代码全部失效
printf("me16 = %" "d" "\n", me16);
printf("me16 = %d\n", me16)
a) 把一个类型的数值初始化给不同类型的变量时,编译器会把值转换成与变量匹配的类型,这将导致部分数据丢失 >>
int cost = 12.99; /* 用double类型的值初始化int类型的变量 */ float pi = 3.1415926536; /* 用double类型的值初始化float类型的变量 */
当缓冲区满、遇到换行字符或需要输入的时候(从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区)