C语言中数据类型所占字节数与它取值范围的关系
请问它是通过什么公式换算成的?
具体的原理是什么?
请哥们解答解答。 展开
C语言中的数据类型,简单的可以分为整数类型和浮点数类型。所占字节数与取值范围的关系实际上是整数编码和浮点数编码的问题,整数编码的三种方式是原码、反码、补码,很容易理解,浮点数的编码格式使用的是IEEE754编码。
1、整数编码以字符类型为例。
字符类型占1个字节,共8位二进制bit位,因此排列组合数,有2^8 = 256种编码的方法。如果表示无符号字符类型,那一般来说表示【0,255】这256个数。
如果表示有符号char类型,如果表示正数,那最高位符号为0,因此可表示的最正整数是:
0-111 1111 ,转化成十进制就是127。同样的道理,符号为1表示负数。最小的负数是
1-000 0000,转化成十进制数就是-128,因此有符号char类型表示的范围是[-128,127]。
一般来说,假设整型数据类型占的二进制位数n,如果表示无符号整数则取值范围是[0,2^n-1],如果表示有符号整数,【-2^(n-1) , 2^(n-1) - 1] 。
2、浮点数类型
浮点数编码一般采用的是IEEE754的编码规则,这个编码格式主要指出了浮点数有效数字、指数以及符号位所占的二进制位数。简单概括为:
格式 长度 符号位 指数位 尾数位 有效位数 指数偏移 尾数说明
单精度 32 1 8 23 24 127 有一位隐含位
双精度 64 1 11 52 53 1023 有一位隐含位
扩展双精度 80 1 15 64 64 16383 没有隐含位
注意:扩展双精度格式没有隐含位,因此它的有效位数与尾数位数一致,而单精度和双精度格式均有一位隐含位,因此它们的有效位数比尾数位数多1。
一般很少自己手动来算浮点数的取值范围,可以使用如下程序来计算。
#include <stdio.h>
typedef struct FP_SINGLE
{
unsigned __int32 fraction : 23;
unsigned __int32 exp : 8;
unsigned __int32 sign : 1;
} fp_single;
typedef struct FP_DOUBLE
{
unsigned __int64 fraction : 52;
unsigned __int64 exp : 11;
unsigned __int64 sign : 1;
} fp_double;
typedef struct FP_EX_DOUBLE
{
unsigned __int64 fraction;
unsigned __int32 exp : 15;
unsigned __int32 sign : 1;
} fp_ex_double;
int main()
{
float x;
fp_single * fp_s = (fp_single *)&x;
fp_s->sign = 0;
fp_s->exp = 0xfe;
fp_s->fraction = 0x7fffff;
printf ("float 最大数: %le\n",(double)x);
fp_s->sign = 0;
fp_s->exp = 0x1;
fp_s->fraction = 0x0;
printf ("float 最小数: %le\n",(double)x);
fp_s->sign = 0;
fp_s->exp = 0;
fp_s->fraction = 0x1;
printf ("float 最小弱规范数:%le\n\n",(double)x);
double y;
fp_double * fp_d = (fp_double *)&y;
fp_d->sign = 0;
fp_d->exp = 0x7fe;
fp_d->fraction = 0xfffffffffffff;
printf ("double 最大数: %le\n", y);
fp_d->sign = 0;
fp_d->exp = 0x1;
fp_d->fraction = 0x0;
printf ("double 最小数: %le\n", y);
fp_d->sign = 0;
fp_d->exp = 0;
fp_d->fraction = 0x1;
printf ("double 最小弱规范数:%le\n\n", y);
char ch[10];
fp_ex_double * fp_ex_d = (fp_ex_double *)ch;
fp_ex_d->sign = 0;
fp_ex_d->exp = 0x7ffe;
fp_ex_d->fraction = 0xffffffffffffffff;
// 不知道扩展双精度浮点数如何输出,
// 不过可以用od跟踪,然后找到ch[0]的地址,在数据窗口中选择 浮点 80为长双精度,
// 就可以看到数值了。
fp_ex_d->sign = 0;
fp_ex_d->exp = 0x1;
fp_ex_d->fraction = 0x8000000000000000;
fp_ex_d->sign = 0;
fp_ex_d->exp = 0;
fp_ex_d->fraction = 0x1;
return 0;
}
顺便说一下,现在好多编译器里的int都是32位的,即int和long int是一样的。
若是有符号的int,那么除去一个符号位,还有15位,
所以取值范围是
非负数:2^15-1 到 0
负数:-1 到 - 2^15
所以int的取值范围是 -32768到32767
如果是无符号的int,那么取值范围是2^16-1 到0
就是 0到65535
2的16次方