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個字節。

如有錯誤,請指出來。謝謝




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