《C语言程序设计:问题与求解方法》——3.8节不同类型数据之间的类型转换

简介:

本节书摘来自华章社区《C语言程序设计:问题与求解方法》一书中的第3章,第3.8节不同类型数据之间的类型转换,作者:何 勤,更多章节内容可以访问云栖社区“华章社区”公众号查看

3.8 不同类型数据之间的类型转换
机器语言的算术运算指令比C语言算术表达式的限制更多。为了让计算机执行机器指令中的算术运算,通常不仅要求两个操作数有相同的长度(字节数),而且还要求数据的存储方式也相同。比如同是单精度浮点型数。
在C语言中,最好把同类型的常量值赋给同一类型的变量,或者使用同类型的常量和变量进行算术运算或关系运算。
然而在C语言程序中,允许在表达式中混合使用各种不同类型的数据。在一个表达式中,可以同时出现整型、浮点型、字符型的常量和变量。在这种情况下,C语言编译程序通常需要生成一些附加的指令,在执行一条运算类指令之前,将其中一个操作数的类型转换成另一个操作数的类型。
下面讨论的类型转换都是有符号型的变量和常量之间的类型转换,不涉及无符号的变量(和常量)。这适用于常规的编程应用范围。一些高级语言(比如Java语言),就只有有符号型的常量和变量。
类型转换分为自动类型转换和强制类型转换两种。自动类型转换指的是编译器在将语句(或表达时)翻译成指令时,由编译程序自动进行的类型转换。在以下四种情况中会出现自动类型转换:
1)二元算术运算符或关系运算符两边的操作数类型不一致。
2)赋值运算符两边的操作数类型不一致。
3)函数调用时实际参数与形式参数要求的类型不一致。
4)函数调用结束时返回值的类型与要求的类型不一致。
其中,第3种和第4种类型转换讨论,请参见第7章。
本章以下仅讨论前两种情况下的自动类型转换。
(1)算术或关系表达式中的类型转换
在算术(或者关系)表达式中,出现在二元运算符两侧的运算量可以是不同类型的,这时就涉及类型之间的转换问题。如果没有出现强制类型转换,那么简单的自动类型转换规则分为三种:
1)只要两个操作数中出现了char类型或 short 型,首先都将无条件地自动提升为int型。
2)在两个操作数的类型都不是浮点型的情况下,自动进行了第一种规定的无条件的类型提升之后,按照以下方式对操作数的类型再次进行有条件的提升。这个条件是两个操作数之中有一个数是long型,即将int提升为long型。
举例来说,对于“short n1 ; long num;”,要求计算表达式n1 + num。编译器先将变量 n1自动提升为int型。由于两个操作数中有一个变量num是long型,因此,刚刚提升为int 型的变量n1的值将再次提升为long型。
延伸与拓展:整型类型提升的技术内幕
增加临时存放此数的字节和对这些字节进行符号位的扩展,这是由于计算机是用补码来表示有符号整数的。只有对补码进行符号位的扩展,补码表示的值才不会改变。参见本章提高部分有关补码的讨论。
3)两个操作数都是浮点数或者其中有一个是浮点数的情况下,提升规则如下:
long double (这是C99标准规定的类型)

AI 代码解读

double

AI 代码解读

float
也就是说:
如果在一个表达式(或一个二元算数或关系运算符)中出现了long double 型的运算量,则此表达式计算出的最终值是long double型的。
如果一个表达式(或一个二元算数或关系运算符)中出现了double 型的运算量(但没有出现long double型量),则此表达式计算出的最终值是double型的。
如果一个表达式(或一个二元算数或关系运算符)中出现了float 型的运算量(但没有出现double型量或long double型量),则此表达式计算出的最终值是float型的。
如果两个操作数中还有一个int型或 long 型的整型量,那么此整型数就会根据另一个浮点操作数的类型进行转换。
读者还要注意的是:数据类型的转换,并不是在计算表达式的值之前一次性完成的,而是根据规定的运算顺序,逐步进行类型转换的。例如,对于如下表达式:
56.91+'A'*32
是先按照转换规则,将char型的量'A'转变为int型值(第一种类型提升)进行乘法运算;得到一个整数值以后,再按照转换规则转变成double型(这是由于前一个参与运算的常量59.61被系统默认为double型常量),然后再与56.91进行双精度浮点数加法运算。
(2)赋值语句(或赋值表达式)中的类型转换
在赋值语句(或赋值表达式)中,如果赋值运算符右边表达式计算结果的类型与左边变量的类型不一致,则会自动进行类型转换。类型转换的规则很简单:将表达式计算出的值转变成赋值号左边变量的类型。
如果赋值号右边的数据类型的取值范围宽于左边变量类型的取值范围,通常会发生精度的额外丢失或者错误。
例如,如果定义“char d_char ; int d_int ; float d_float ; double d_double ;”,那么以下赋值语句(或赋值表达式)是不会有任何问题的,因为右边的数据类型“不宽于”左边变量类型的取值范围。
d_int = d_char;
d_float = d_int;
d_double = d_float;
但是,如果将以上几条赋值语句(或赋值表达式)中的变量调换位置:
d_char= d_int;
d_int =d_float;
d_float= d_double;
通常都会出现问题。
对于第1条语句“d_char= d_int;”,在d_int的值超过255时,在char只占8位内存的计算机上必然出错(溢出)。即使d_int的取值在128~255之间,也不一定正确。这要看你正在使用的C编译器中,char类型本质上到底是有符号的整数(取值在–128~127之间)还是无符号的整数(取值在0~255之间)。如果是前者,就会出现把一个正整数变成了一个负整数并且存放到变量d_char中的错误。
对于第2条语句“d_int =d_float;”,必然会使d_float的小数部分丢失(不会四舍五入)。更为严重的是,如果d_float的值超出了int类型的取值范围(这或许是很常见的,因为有些C编译器中,int型的最大值是32767),那么变量d_int中的值也必然出错(溢出)。
第3条语句的情况,读者可自行分析。
(3)强制类型转换
如果自动类型转换满足不了需要,则可以要求编译程序进行强制类型转换。强制类型转换是通过使用强制类型转换运算符(由圆括号括住类型名构成)来实现的。其格式为:
(类型名)(被转换的表达式)
其功能是把表达式的运算结果,强制转换成类型名所给定的类型。例如,(float) m 把整型变量m的值强制转换为单精度浮点型。(int)(3.86x–y)把表达式3.86x–y的值强制转换为整型。
在进行强制类型转换时应注意:类型名必须用圆括号括住,不能省略;需进行类型转换的表达式也要加圆括号(单个变量或常量可以不加括号)。例如,如果错把(int)(x–y)写成(int)x–y,则会出现仅仅把x转换成int类型之后,再与y相加的问题。
以下两种情况下要使用强制类型转换:
1)如果担心两个float型量x,y的乘积超出float型的表示范围(即产生溢出),那就要这样书写语句:z=(double )xy;。其中,变量z是double类型,y的类型会自动提升为double型。注意,另一个很类似的语句:z=(double )(xy);是错误的,因为在进行强制类型转换前,x*y的乘积值很可能已经超出了float型的表示范围。
2)如果担心两个int型量i,j的乘积超出int型的表示范围,那就要这样书写语句: k=(long int )i*j;,其中k是long int类型的变量。
强制类型转换如果使用不当,出现的问题与赋值语句中自动类型转换的类似。
注意:无论是强制类型转换或是自动类型转换,都只是为了本次运算的需要而对从变量中取出的值进行的临时性转换,不会改变变量定义时对该变量指定的类型,也不会改变变量所对应内存单元中存放的值。
无符号的变量(和常量)之间的类型转换,与本节讨论的情况完全类似。强烈建议读者在通常应用中不要在表达式中使用无符号的常量与变量。无符号的常量和变量最好局限于应用在系统编程和嵌入式编程方面。所以,读者应尽量避免在同一个表达式中,同时使用有符号和无符号的量。无符号与有符号量之间的类型转换的讨论,请读者参考相关的教科书。

目录
打赏
0
0
0
0
1408
分享
相关文章
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
36 3
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
20 2
|
1月前
|
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
65 16
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
52 1
|
1月前
|
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
77 18
|
1月前
|
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
52 13
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
57 18
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
69 10
|
1月前
|
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
40 10
|
1月前
|
【C语言程序设计——循环程序设计】利用数列的累加和求 sinx(头歌实践教学平台习题)【合集】
项的累加和,一般会使用循环结构,在每次循环中计算出当前项的值(可能基于通项公式或者递推关系),然后累加到一个用于存储累加和的变量中。在C语言中推导数列中的某一项,通常需要依据数列给定的通项公式或者前后项之间的递推关系来实现。例如,对于一个简单的等差数列,其通项公式为。的级数,其每一项之间存在特定的递推关系(后项的分子是其前项的分子乘上。,计算sinx的值,直到最后一项的绝对值小于。为项数),就可以通过代码来计算出指定项的值。对于更复杂的数列,像题目中涉及的用于近似计算。开始你的任务吧,祝你成功!
48 6

热门文章

最新文章