网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
7.1.4 整数溢出
有符号整数运算中发生溢出时,程序的行为是未定义的。
无符号整数运算过程中发生溢出时,结果是有定义的:正确答案是对2n取模,其中n是用于存储结果的位数。例如,如果无符号的16位数65535加1,其结果可以保证为0。
7.1.5 读/写整数
假设有一个程序因为其中一个int变量发生溢出而无法工作。我们的第一反应是把变量的类型从int变为long int。但仅仅这样是不够的,我们还必须检查数据类型的改变对程序其它部分的影响,尤其是需要检查该变量是否用在printf函数或者scanf函数的调用中。如果用了,需要改变调用的格式串,因为%d只适用于int类型。
- 读/写无符号整数时,使用字母u、o或x代替转换说明中的d。如果使用u说明符,该数将以十进制形式读写,o表示八进制形式,而x表示十六进制形式。
- 读写短整数时,在d、o、u或x前面加上字符h。
- 读写长整数时,在d、o、u或x前面加上字符l。
- (C99)读写长长整数时,在d、o、u或x前面加上字母ll。
7.2 浮点类型
long double支持极高精度的要求,很少会用到。
7.2.1 浮点常量
默认情况下,浮点常量都以双精度的形式进行存储。
为了表明只需要单精度,可以在常量的末尾处加上字母F或f;而为了说明常量必须以long double格式存储,可以在常量的末尾处加上字母L或l。
7.2.2 读/写浮点数
转换说明符%e、%f和%g用于读写单精度浮点数。
C99允许printf函数调用中使用%le、%lf和%lg,不过字母l不起作用。
7.3 字符类型
字符常量需要用单引号括起来,而不是双引号。
7.3.2 有符号字符和无符号字符
标准C允许使用单词signed和unsigned来修饰char类型:
unsigned char x;
signed char x;
可移植性技巧 不要假设char类型默认为signed或unsigned。如果有区别,用signed char或unsigned char代替char。
7.3.4 转移序列
名称 | 转义序列 |
---|---|
警报(响铃)符 | \a |
回退符 | \b |
换页符 | \f |
换行符 | \n |
回车符 | \r |
水平制表符 | \t |
垂直制表符 | \v |
反斜杠 | \ |
问号 | ? |
单引号 | \’ |
双引号 | " |
- 八进制转义序列由字符\和跟随其后的一个最多含有三位数字的八进制数组成。(此数必须表示为无符号字符,所以最大值通常是八进制的377。)例如,可以将转义字符写成\33或\033。跟八进制常量不同,转义序列中的八进制数不一定要用0开头。
- 十六进制转义序列由\x和跟随其后的一个十六进制数组成。虽然标准C对于十六进制数的位数没有限制,但必须表示成无符号字符(因此,如果字符长度是8位,那么16进制数的值不能超过FF)。若采用这种表示法,可以把转义字符写成\x1b或\x1B的形式。字符x必须小写,但是十六进制的数字(例如b)不限大小写。x不可省略。
7.3.5 字符处理函数
toupper()函数在被调用时检测参数是否为小写字母,如果是,他会把参数转换成相应的大写字母;否则,该函数会返回参数的值。
调用toupper函数的程序要添加预处理指令包含相应的头文件<ctype.h>。
7.3.6 用scanf和printf读/写字符
scanf函数不会跳过空白字符。为了强制scanf函数在读入字符前跳过空白字符,需要在格式串中的转换说明%c前面加上一个 空格。
注意:scanf格式串中的空白意味着“跳过零个或多个空白字符”。
7.3.7 用getchar和putchar读/写字符
注意:getchar含糊返回的是一个int类型的值而不是char类型的值。和scanf函数一样,getchar函数也不会在读取时跳过空白字符。
在执行程序时,使用getchar函数和putchar函数可以节约不少时间(胜于scanf和printf)。原因有两个:
- 这两个函数比scanf函数和printf函数简单的多,因为scanf函数和printf函数时设计用来按照不同的格式读/写多种不同类型的数据的。
- 为了额外的速度提升,通常getchar函数和putchar函数是作为宏来实现的。
惯用法:
while(getchar()!='\n')
···
while((ch = getchar())==' ')
···
7.4 类型转换
隐式转换:
- 当算术表达式或者逻辑表达式中操作数的类型不相同时。(C语言执行所谓的常用算术转换)
- 当赋值运算符右侧表达式的类型和左侧变量的类型不匹配时。
- 当函数的调用中的实参类型与其对应的形参类型不匹配时。
- 当return语句中表达式的类型和函数返回值的类型不匹配时。
7.4.1 常用算术转换
整值提升:它把字符或短整型整数转换成int类型(或者某些情况下是unsigned int类型)。
整值提升有下列两种情况:
- 任一操作数的类型是浮点类型的情况。按照下图将类型较狭小的操作数进行提升:
注意:只要双目运算符左右的数据有一个的类型是某一个类型,那么另一个比其等级低的类型将会向上进行转换。也就是说,如果一个操作数的类型为long double,那么另一个操作数的类型转换成long double。
- 两个操作数的类型都不是浮点类型的情况。首先对其两个操作数进行整值提升(保证没有一个操作数的是字符类型或短整型)。然后按照下图对类型较狭小的操作数进行提升:
有一种特殊情况,只有在long int类型和unsigned int类型长度(比如36位)相同时才会发生。在这种情况下,如果一个操作数的类型是long int,而另一个的类型是unsigned int,那么两个操作数都会转换成unsigned long int类型。
注意:strlen()函数和sizeof()操作数的类型都是unsigned int类型。
7.4.2 赋值过程中的转换
常用算术转换不适用于赋值运算。C语言会遵循另一条简单的转换规则,那就是把赋值运算右边的表达式转换成左边变量的类型。如果变量的类型至少和表达式类型一样“宽”,那么这种转换都将没有任何障碍。当然,把某种类型的值赋给类型更狭小的变量,也将会得到无意义的结果。
下面是一个例子:
int a = 0;
unsigned x = 5;
int y = 5;
a = x + y;
//上面这个表达式将会发生两次类型转换,第一次,y将从有符号类型转换为有符号类型,第二次,x+y表达式的结果,将从无符号类型转换成有符号类型。
7.4.3 C99中的隐式转换
为了定义转换规则,C99中允许每个整数类型具有“整数转换等级”。下面按从最高级到最低级的顺序排列。
- long long int、unsigned long long int
- long int、unsigned long int
- int、unsigned int
- short int、unsigned short int
- char、signed char、unsigned char
- _Bool
C99用整数提升取代了C89中的整值提升,可以将任何等级低于int和unsigned int的类型转换为itn(只要该类型的所有值都可以用int类型表示)或unsigned int。
C99中执行常用算术替换的规则可以划分为两种情况:
- 任一操作数的类型是浮点类型的情况。只要两个操作数的都不是复数型,规则与前面一样。
- 两个操作数的类型都不是浮点类型的情况。首先对两个数进行整数提升,如果这时两个操作数的类型相同,过程结束。否则,依次尝试下面的规则,一旦遇到可应用的规则就不再考虑其它的规则:
- 如果两个操作数都是有符号型或者都是无符号型,将整数转换等级较低的操作数转换为等级较高的操作数的类型。
- 如果无符号数的等级高于或等于有符号操作数的等级,将有符号操作数转换为无符号操作数的类型。
- 如果有符号操作数类型可以表示无符号操作数类型的所有值,将无符号操作数转换为有符号操作数的类型。
- 否则,将两个操作数都转换为与有符号操作数的类型相对应的无符号类型。
另外,==所有算术类型都可以转换为_Bool类型。==如果原始值为0则转换结果为0,否则结果为1。
7.4.4 强制类型转换
- C语言把(类型名)视为一元运算符。一元运算符的优先级高于二元运算符。所以编译器会把表达式
(float)dividend / divisor
解释为
((float)dividend)/divisor
- 有时候,需要使用强制类型转换来避免溢出。
long i;
int j = 1000;
i = j*j;
当两个int类型值相乘时,结果也应该是int类型的,但是j*j的结果太大,以致在机器上无法表示成int型,从而导致溢出,此时就可以使用强制类型转换避免这种问题的发生:
i = (long)j*j;
7.5 类型定义
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
0004145)]
[外链图片转存中…(img-UjeAFDyj-1715820004145)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!