32bit,64bit 变量长度
类型 | 32bit | 64bit |
---|---|---|
char | 1 | 1 |
float | 4 | 4 |
int | 4 | 4 |
short | 2 | 2 |
double | 8 | 8 |
long | 4 | 8 |
long long | 8 | 8 |
void * | 4 | 8 |
long double | 12 | 16 |
结构体的对齐
结构体大小的计算方法和步骤: - 数据类型自身的对齐值,对于char,自对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4字节。 - 结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值 - 指定对齐值:#pragma pack(value)指定对齐value. - 数据成员,结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
注意:结构体或类中的静态成员不对结构体或类的大小产生影响。因为其储存在.data 没有成员变量的结构体或类的大小为1,因为必须保证让每一个实例在内存中有唯一的地址。
例子
#pragma pack(2)
struct s1
{
char a; //1
int b; //2*2
short c; //2
}
/**************************************/
[]* _____char a
* *
* * _____int b
* * _____short c
sizeof(s1) == 8;
#pragma pack(8)
struck s2
{
char a; //1
int b; //4
short c; //2
}
struck s3
{
struck s2 s2;
char b;
int c
}
sizeof(s2) == 12
sizeof(s3) == 20
联合体
- 1.联合体是一个结构
- 2.它的所有成员相对于基地址的偏移量为0
- 3.结构体空间要大到足够容纳最宽的成员
- 4.其对齐方式要适合其中所有成员
- 5.大小能被包含所有基本数据类型大小所整除
/*
* =====================================================================================
*
* Filename: union.c
*
* Description: 联合体测试程序
*
* Version: 1.0
* Created: 2014年04月01日 17时04分13秒
* Revision: none
* Compiler: gcc
*
* Author: izobs (Lin), ivincentlin@gmail.com
* Organization:
*
* =====================================================================================
*/
#include <stdlib.h>
#include <stdio.h>
typedef union U1
{
char s[9];
int n;
double d;
}U1;
typedef union U2
{
char s[5];
int n;
double d;
}U2;
int main(int argc, char *argv[])
{
U1 u1;
U2 u2;
printf("%d\n",sizeof(u1));
printf("%d\n",sizeof(u2));
printf("0x%x\n",&u1);
printf("0x%x\n",&u1.s);
printf("0x%x\n",&u1.n);
printf("0x%x\n",&u1.d);
u1.n=1;
printf("%d\n",u1.s[0]);
printf("%lf\n",u1.d);
unsigned char *p=(unsigned char *)&u1;
printf("%d\n",*p);
printf("%d\n",*(p+1));
printf("%d\n",*(p+2));
printf("%d\n",*(p+3));
printf("%d\n",*(p+4));
printf("%d\n",*(p+5));
printf("%d\n",*(p+6));
printf("%d\n",*(p+7));
return 0;
}
结果:
16
8
0x22341fb0
0x22341fb0
0x22341fb0
0x22341fb0
1
1
0
0
0
0
0
0
0
浮点数值的存储
浮点数:R=M*2^e > R:real M:尾数 e:阶码
float: x xxxxxxxx xxxxxxxxxxxxxxxxxx [符号位] [阶码8,e=E-127] [尾数23]
float的二进制转换计算
例子
float 125.5的32二进制码为(小数部分转为二进制,将小数部分不断乘2,取整):
如:0.52 = 1,取整0.100000
则125.5的二进制数为:111 1101.1,科学计数表示为1.1111012^6.
向左移6,e为正数,e = 6,E = e +127,E 二进制为10000101.
而1.111101去除1后为 111101,后面补0,共23bit。形成阶码。
则125.5的32二进制如:
> 0 10000101 11101 000000000000000000000
例子2:int转float
> int a = 3490593;
> float b = (float)a;
那么在内存中a和b究竟存放的是什么值呢?
将a展开为二进制,其值为0000 0000 0011 0101 0100 0011 0010 0001,其十六进制即为0x00354321。 因为要转化为float型,所以首先要对上述二进制的表示形式改变为 M * 2^E 的形式.由于该数明显大于1,所以按照IEEE的标准,其浮点形势必然为规格化值。因此 ,转化后的形式为
> a = 1.101010100001100100001 * 2^21
根据 规格化值的定义,M = 1 + f. 所以f = 0.101010100001100100001.因为float型变量的小数域一共23位。所以b的最后23位可以得出,其值为10101010000110010000100
下面再演绎指数域的值:因为a的指数表示法中,指数e = 21。根据公式2,E = e + (2^7 -1) = 148.所以可以得出b的指数域的二进制表示为:10010100。在加上原数为正,所以符号位s=0。
所以,可以得出b的二进制表示为0 10010100 10101010000110010000100。转化为十六位进制则是0x4A550C84。换句话说,它存储在内存中的值是与a是完全不同的。但是其间还是有关联性的——a的首位为1的数值位后的二进制表示是与b的小数域完全相同的。
很快,问题就出现了。int型的有效位数是31,而float型小数域的有效位只有23位,也就是说如果上面的a的二进制的有效位超过了24位,那么float型的小数域的精度就不够了。因此必须进行舍入。比如:如果上面的a的二进制为0000 0001 1111 0101 0100 0011 0010 0001。这时b的小数域必须有24位才够,但是,这显然是不现实的,因此必须舍入到23位,舍入的原则是:所得结果的最低有效位为0。因此这个a在转换到float时,其精度就会丢失,因为该float的最后23位变成了11110101010000110010000——这显然是与原值不符的。
实际上,C语言中对于double型在32位机器上的小数域有52位,对于int型的31位有效位是绰绰有余了。这就是为什么大部分C语言教材上鼓励读者在执行强制类型转换时将int型转换成double。同时,这可能也是为什么int型能够直接隐式转换到double型的缘故。