c语言里的简单类型只有两类,整数型 和浮点型:
整数型: char 1
short 2
int 4
long 4
浮点型 :float 4
double 8
C语言里并没有规定short int 和 long各自占都少个字节,他们只要求满足下面的关系:
short占用空间《= int 占用空间 《= long 占用空间
而按照约定,int 的大小一般刚好占用一个机器字节,所以就有了上述的结果。
问题就有了,如果不同类型之间相互赋值,C语言是如何处理的??
#1,相同种类变量(同时整型或者浮点型)之间相互赋值:
当然float 和double之间的赋值大家都很清楚,float赋值double可以,但是反过来就会丢失精度。
我今天想说的重点是char 和 int 之间:(尤其是作嵌入式平台容易出现错误)
首先,我们都知道整型有signed 和unsigned之分。
当你写 :char c; 实际上是 signed char c; 占用一个字节
char c =0x80;
int i= c;
这是 i的值竟然是-128.下面是在centos上调试的结果:
#include <stdio.h>
int main(void)
{
char c=0x80;
int i=c;
printf("i=%d.\n",i);
return 0;
}
编译运行的结果:
[adminiter@trageday bolg]$ gcc 02.c
[adminiter@trageday bolg]$ ./a.out
i=-128.
为啥会这样呢?
因为c是signed char ,而0x80(二进制表示是:1000_0000)最高位是‘1’,所以C 是负数,(带符号)扩展成32位变成0xFFFF_FF80,把这个赋值给i,i当然就是负数了。
但如果这样写:
unsigned char c=0x80;
int i=c;
这是i就是128.
在据一个例子:
int i=5;
int u=i;
这个赋值是肯定没有问题的,
但是:
int i=5;
unsigned u=i;
就有可能出现问题,是可能啊。例:
int i=-5;
unsigned u=i;
u的结果是多少呢?
u=4294967291.
原因和上面个那个差不多,首先编译器把-5转换成二进制0xFFFF_FFFB 赋值给了i,然后把 i的值赋值给了u,所以最后u仍然等于0xFFFF_FFFB。值还是那个值,但是有u的(unsigned)解释出来就是4294967291。
这就是C语言对赋值的处理。只是简单的符号扩展(有符号)然后把二进制拷贝,然后使用对方的“格式”解释。当然,占内存不同的类型之间会存在空间取舍。
复合类型:
C语言提供了几种复合类型:struct(结构体),union(共用体)和bit field (位域)。结构体和共用体使用的组多的,这里我就不重复它们的使用方法,只讨论几个有意思的问题(关于内存对齐的问题)alignment(对齐)
例:
#include <stdio.h>
struct s
{
char c;
int i;
};
int main(void)
{
printf("sizeof(struct s)=%d.\n",sizeof(struct s));
return 0;
}
运行调试结果如下:
[adminiter@trageday bolg]$ gcc 02.c
[adminiter@trageday bolg]$ ./a.out
sizeof(struct s)=8.
解释这个之前,我们要了解alignment(对齐)的概念。
CPU对内存的访问并不是完全任意的,如果CPU相一次读(写)4个字节,那给出的内存地址最好是4的倍数,例如:
0x12345670
0x12345674
0x12345678
0x1234567c
十六进制下,最低位一定是0 ,4 , 8,c 这样四的倍数结尾的,CPU只需要通过一次访问就可以得到完整的数据。否则,CPU就要通过多次操作才能完成一次完整的存取。例如:
我们要求CPU从0x12345672 读取4个自己到寄存器,CPU只能这样做:
第一步,从0x12345670读4个字节,舍弃掉16位数据,把剩下的高16位存起来。
第二步 , 从0x12345674读4个字节,舍弃掉16位数据,和上一次取的数据共同组成32位要取的数据。
可以看出,如果不对数据做出特别的安排,CPU对数的访问就会缺乏效率。为了提高效率,编译器一般都会把数据放到合适自己的位置上。譬如,int 占4字节,所以int变量的地址都是4的倍数,这个就称作 “4字节对齐”。
所以我们平时写结构体时应该注意点字节对齐问题,如:
struct s
{
char x;
int y;
char z;
int u;
};
结构体s 占用16字节。
struct s1
{
int y;
int u;
char x;
char z;
};
结构体s1 占用12字节。
还有一个值得注意的问题:
这个结构体占用多少字节呢?
struct s
{
int y;
char z;
};
可能有人说是5字节,一个4字节对齐,一个1字节对齐。共5字节。X X X X X X X X
其实正确答案是8字节。
原因和上面的差不多,还是数据对齐的缘故。试想下,如果我写个:
struct s array【10】;
则array是由10个s组成的,这10个s必须依次安排在一块连续的区域。那样的话,如果s占用5个字节,问题就是array【0】还可以,但是array【1】的字节就不是对齐的了。后面的就更是乱套的。
所以最后整个结构体还要按照数据成员占内存最大的成员进行对齐。按上面例子就是 :
5字节数据 按4字节对齐存储,就是8个字节。
如有错误,请指出来。谢谢