让我们首先来分析,下列源程序中的变量在机器内是如何表示的,以及各变量对应的十进制真值是多少,无符号数和带符号整数的扩展操作方式是否相同?各是如何进行的?
#include
int main()
{
short si = -32768;
unsigned short usi = si;
int i = si;
unsigned ui = usi;
printf("%d\n", si);
printf("%u\n", usi);
printf("%d\n", i);
printf("%u\n", ui);
return 0;
}
0
表示正数,1
表示负数。short si = -32768;
• si
是一个有符号短整型变量,占用2个字节(16位)。
• 十进制真值:-32768
。
• 扩展操作方式:将-32768
直接存储到 si
中,不需要进行扩展操作。
unsigned short usi = si;
• usi
是一个无符号短整型变量,占用2个字节(16位)。
• 十进制真值:32768
。
• 扩展操作方式:将 si
的二进制补码表示直接转换为无符号数的二进制表示。
int i = si;
• i
是一个有符号整型变量,占用4个字节(32位)。
• 十进制真值:-32768
。
• 扩展操作方式:由于 si
是一个有符号短整型变量,它的扩展操作是将其符号位扩展到更高位,即复制符号位,直到填满 i
的所有位。
unsigned ui = usi;
• ui
是一个无符号整型变量,占用4个字节(32位)。
• 十进制真值:32768
。
• 扩展操作方式:将 usi
的二进制表示直接转换为无符号整数的二进制表示。
综上所述,无符号数和带符号整数的扩展操作方式是不同的。无符号数直接将二进制表示转换为目标类型,而带符号整数需要进行符号位的扩展操作。
short
型数据 -12345
,分别转换为int、unsigned short、unsigned int、float
类型的数据;#include
int main() {
short s = -12345;
int i = s;
printf("s as int: %d\n", i);
unsigned short us = (unsigned short)s;
printf("s as unsigned short: %u\n", us);
unsigned int ui = (unsigned int)s;
printf("s as unsigned int: %u\n", ui);
float f = (float)s;
printf("s as float: %f\n", f);
return 0;
}
由于short
类型是有符号的,而unsigned short
和unsigned int
都是无符号的,因此s
转换为unsigned short
和unsigned int
时会被解释为一个很大的正整数
在进行float
类型的转换时,系统会将short
类型的值转换为float
类型的值,并在其末尾添加一些额外的零,以使其符合float
类型的规格化格式。
int
型数据2147483647
,分别转换为short、unsigned short、unsigned int、float、double
类型的数据;#include
int main() {
int i = 2147483647;
short s = (short)i;
printf("i as short: %d\n", s);
unsigned short us = (unsigned short)i;
printf("i as unsigned short: %u\n", us);
unsigned int ui = (unsigned int)i;
printf("i as unsigned int: %u\n", ui);
float f = (float)i;
printf("i as float: %f\n", f);
double d = (double)i;
printf("i as double: %lf\n", d);
return 0;
}
在32位系统中,int
类型占据4个字节,范围为-2147483648
到2147483647
。
当将最大值2147483647
转换为short
类型时,超出了short
类型的范围,导致截断,结果为-1
。
当将最大值2147483647
转换为unsigned short
类型时,超出了unsigned short
类型的范围,结果为65535
。
当将最大值2147483647
转换为unsigned int
类型时,结果仍然是2147483647
,因为unsigned int
类型足够存储这个数值。
当将最大值2147483647
转换为float
类型时,由于float
类型的精度限制,整数部分超过了可表示的范围,结果变为2147483648.000000
。
当将最大值2147483647
转换为double
类型时,double
类型的精度比float
更高,能够保持原始值。
float
型数据123456.789e5
,转换成int、double
型数据;#include
int main() {
float f = 123456.789e5;
int i = (int)f;
printf("f as int: %d\n", i);
double d = (double)f;
printf("f as double: %lf\n", d);
return 0;
}
在32位机器上,int
类型占据4个字节,范围为-2147483648
到2147483647
。而变量f的值为123456.789e5
,即123456.789
乘以10
的5
次方,结果为12345678900
。
当将float
类型的变量f
转换为int
类型时,会发生截断操作。由于整数部分超过了int
类型的范围,截断结果为-2147483648
,即int
类型的最小值。
当将float
类型的变量f转换为double
类型时,由于double类型的精度比float
更高,能够准确表示变量f的值。因此,结果为12345679104.000000
。
double
型数据123456.789e5
,转换成int、float
型数据。#include
int main() {
double d = 123456.789e5;
int i = (int)d;
printf("d as int: %d\n", i);
float f = (float)d;
printf("d as float: %f\n", f);
return 0;
}
在32位机器上,int
类型占据4个字节,范围为-2147483648
到2147483647
。而变量d
的值为123456.789e5
,即123456.789
乘以10
的5
次方,结果为12345678900
。
当将double
类型的变量d
转换为int
类型时,会发生截断操作。由于整数部分超过了int
类型的范围,截断结果为2147483647
,即int
类型的最大值。
当将double
类型的变量d
转换为float
类型时,由于float
类型的精度较低,无法完全保留double
类型的精度。因此,结果为12345679232.000000
,存在舍入误差。
int
型数)是否总能转换为等值的float
类型数据?为什么?补码整数(如int
型数)并不总能转换为等值的float
类型数据。这是因为在转换过程中,如果整数部分过大或者过小,超出了float
类型能表示的范围,就会发生精度丢失或者溢出的情况。例如,在32位机器上,int
类型范围为-2147483648
到2147483647
,而float
类型的有效范围约为±3.4e±38
,当int型数据超出了这个范围时,就无法准确表示为对应的float
类型数据。
float
型数据是否总能转换成等值的double
型数据?为什么?float
型数据并不总能转换成等值的double
型数据。虽然float和double
都表示浮点数,但是double
类型具有更高的精度和表示范围。因此,当一个float
类型数据转换为double
类型时,会出现精度损失的情况,因为double
类型无法准确表示所有的float
类型数据,特别是对于较大或较小的浮点数。
将长数截断为短数后,可能发生精度丢失或溢出的现象。例如,将一个较大的double
类型数据截断为float类型,或者将一个int
类型数据赋给short
类型变量,都可能导致数据溢出或者精度丢失。这是因为短数类型能够表示的范围和精度比长数类型更小,所以超出范围的部分会被截断或者舍入,导致数据的改变。
#include
int main() {
unsigned int x = 1;
unsigned int y = 4294967295;
// 1 + 4294967295
unsigned int sum = x + y;
printf("1 + 4294967295 = %u (0x%x)\n", sum, sum);
// 1 - 4294967295
unsigned int diff = x - y;
printf("1 - 4294967295 = %u (0x%x)\n", diff, diff);
return 0;
}
unsigned int
类型的数据是无符号数,范围为0
到4294967295
。由于1
加上4294967295
等于4294967296
,超出了unsigned int
类型的表示范围,因此结果为0
。对于无符号数来说,溢出后会自动回绕,即4294967296
等于0
。1
减去4294967295
的结果为2
。同样地,由于unsigned int类型是循环的,4294967295减去1实际上等于2。#include
int main() {
int a = 2147483647;
int b = 1;
int c = -2147483648;
int d = -1;
// 2147483647 + 1
int sum = a + b;
printf("2147483647 + 1 = %d (0x%x)\n", sum, sum);
// -2147483648 - 1
int diff = c - d;
printf("-2147483648 - 1 = %d (0x%x)\n", diff, diff);
return 0;
}
int
类型的数据是有符号数,范围为-2147483648
到2147483647
。由于2147483647
加上1
等于2147483648
,超出了int类型的表示范围,因此结果为-2147483648
。这是因为在有符号整数中,溢出会导致“环绕”现象。-2147483648
减去1
的结果为2147483647
。由于-1
的补码为0xffffffff
,将-2147483648
减去1
相当于对-2147483648
取反后加1
,得到的就是2147483647
。