C语言学习笔记(4)类型转化,复合类型

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个字节。

如有错误,请指出来。谢谢




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章