結構體中冒號的作用

作者:日月之易

原作網址:http://hi.baidu.com/wz125/item/812c7db407493a76244b09fa

謝謝作者分享

結構體中常見的冒號的用法是表示位域。  

      有些信息在存儲時,並不需要佔用一個完整的字節,   而只需佔幾個或一個二進制位。例如在存放一個開關量時,只有0和1   兩種狀態,   用一位二進位即可。爲了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱爲“位域”或“位段”。所謂“位域”是把一個字節中的二進位劃分爲幾個不同的區域,   並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。   這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。一、位域的定義和位域變量的說明位域定義與結構定義相仿,其形式爲:    

    struct   位域結構名    

    {   位域列表   };  

    其中位域列表的形式爲:   類型說明符   位域名:位域長度    

    例如:    

  struct   bs  
  {  
   int   a:8;  
   int   b:2;  
   int   c:6;  
  };      

    位域變量的說明與結構變量說明的方式相同。   可採用先定義後說明,同時定義說明或者直接說明這三種方式。例如:    

  struct   bs  
  {  
   int   a:8;  
   int   b:2;  
   int   c:6;  
  }data;    

    說明data爲bs變量,共佔兩個字節。其中位域a佔8位,位域b佔2位,位域c佔6位。對於位域的定義尚有以下幾點說明:  

    1.   一個位域必須存儲在同一個字節中,不能跨兩個字節。如一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:    

  struct   bs  
  {  
   unsigned   a:4  
   unsigned   :0   /*空域*/  
   unsigned   b:4   /*從下一單元開始存放*/  
   unsigned   c:4  
  }    

    在這個位域定義中,a佔第一字節的4位,後4位填0表示不使用,b從第二字節開始,佔用4位,c佔用4位。  

    2.   由於位域不允許跨兩個字節,因此位域的長度不能大於一個字節的長度,也就是說不能超過8位二進位。  

    3.   位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:    

  struct   k  
  {  
   int   a:1  
   int   :2   /*該2位不能使用*/  
   int   b:3  
   int   c:2  
  };      

    從以上分析可以看出,位域在本質上就是一種結構類型,   不過其成員是按二進位分配的。  

    二、位域的使用  

    位域的使用和結構成員的使用相同,其一般形式爲:   位域變量名·位域名   位域允許用各種格式輸出。  

  main(){  
   struct   bs  
   {  
    unsigned   a:1;  
    unsigned   b:3;  
    unsigned   c:4;  
   }   bit,*pbit;  
   bit.a=1;  
   bit.b=7;  
   bit.c=15;  
   printf("%d,%d,%d/n",bit.a,bit.b,bit.c);  
   pbit=&bit;  
   pbit->a=0;  
   pbit->b&=3;  
   pbit->c|=15;  
   printf("%d,%d,%d/n",pbit->a,pbit->b,pbit->c);  
  }      

    上例程序中定義了位域結構bs,三個位域爲a,b,c。說明了bs類型的變量bit和指向bs類型的指針變量pbit。這表示位域也是可以使用指針的。  

    程序的9、10、11三行分別給三個位域賦值。(   應注意賦值不能超過該位域的允許範圍)程序第12行以整型量格式輸出三個域的內容。第13行把位域變量bit的地址送給指針變量pbit。第14行用指針方式給位域a重新賦值,賦爲0。第15行使用了複合的位運算符"&=",   該行相當於:   pbit->b=pbit->b&3位域b中原有值爲7,與3作按位與運算的結果爲3(111&011=011,十進制值爲3)。同樣,程序第16行中使用了複合位運算"|=",   相當於:   pbit->c=pbit->c|1其結果爲15。程序第17行用指針方式輸出了這三個域的值。

===================================================================================

 

endian和little
endian但是很少有人知道它們的實質,因爲只要你在網上一google,出來的都是那個經典的典故,不可否認,那個典故很重要,但是那也僅僅是個故事而已,計算機也僅僅是利用了這個故事的名字罷了,說到它們的實質還要看存儲式體系計算機剛開始的時候,那個時候人們紛紛將數據和指令存入內存,如今我們很坦然的說出一個字節八位,一個int型的數據32位,可是那個時候人們在設計這一切的時候卻沒有這麼坦然,他們甚至都不把八位想的這麼特殊,現在想想爲什麼一個字節是八位,爲什麼八位顯得那麼重要,其實這裏並沒有什麼必然的東西,因爲計算機是以二進制爲基礎的,八位一字節在硬件上最簡單,最高效,當時的cpu的數據總線最多也就有8位,而且8位最大可以表示255,正好表示完所有的拉丁字符,可是隨着軟件硬件的進步,而且實際上我們必須表示一個大於255的數字而不是字符,那麼八位的數據量太小了,因此必須用超過一個字節的內存存儲更大的數據類型,這就涉及到如何安排這些多字節數據的字節順序了,因爲邏輯上雖然一個int就是一個整數,但是人們根本不會管它在物理上怎麼被載入內存,應該是怎麼簡單怎麼高效就怎麼安排,就好像邏輯上一個進程有四個G的虛存空間,但是物理上怎麼安排實際分給這個進程的內存就是操作系統的事情了,邏輯上連續物理上不一定連續在字節續上也有所體現,於是怎麼安排多字節的數據就是個問題,像虛擬內存那樣徹底分開然後建立一套映射機制顯得沒有必要,那麼就有了big
endian和little endian這樣的排列方式,以字節爲一個單位,然後安排這些字節的位置,不至於太分散但又不失靈活,這就是策略,於是big
endian和little
endian其實是根據不同的側重點而最終採用的兩種方式罷了,其實現在的計算機已經都是32位的了,8位的基本字節要改變了,但是即使改了也還要面對字節序的問題,畢竟數據類型的大小沒有上限,對於big
endian來說,自然數據的高位在內存的低位,按照cpu發出的訪問指令據總線導致內存訪問的順序是從低地址到高地址的,也就是先訪問到最高的數據位,按照二進制數據的編碼,最高位是符號位,也就是說big
endian的機器最先訪問到符號位,這對於運算來說是很有優勢的,現在看看little endian的情況,正好和big
endian相反,數據總線最先訪問到自然數據的最低位,但是想要的到符號不得不先看看數據佔幾個字節找到最高位,然後才能判定,很麻煩,但是先訪問低位也有好處,比如位訪問比較有效,cpu訪問一個數據的第n位就需要簡單的從該數的開始處移動n/8個位置即可,僅僅一個移位,很簡單,這個特性可以很方便的進行類型轉換,軟件上類型轉換比較頻繁的用little
endian比較有效,而不怎麼需要類型轉換的,數據類型比較固定的就用big endian比較好。

現在我們看一個重要的發現,就是CISC/RISC與big/little
endian的關係,我們知道RISC擁有大量的寄存器,所有的計算都在寄存器進行,只有在load或者store的時候才訪問內存,而這兩個操作僅僅是加載或者存儲一個數字,數字的符號以及大小等信息越容易得到越好,現在看看CISC,由於類型轉換涉及到計算,涉及到一些cpu指令,比如將一個32位的寄存器放到一個16位的臨時數據中,而32位數據的得到涉及到很多尋址方式,很可能數據就是從內存得到的,因此CISC中爲了最快的類型轉換需要最快的位訪問,這就是說,對於CISC的cpu,用little
endian比較好,而對於RISC的cpu,用big endian比較好。

計算機中的很多事情都沒有絕對的爲什麼,很多都是因爲歷史原因,在當時的歷史條件下必須那樣,也許也不是必須那樣,而是因爲那樣更簡單,然後就確定了一些規則,計算機不僅僅是一門科學,它還是一個工業,工業就要兼顧經濟利益,於是向下兼容就很重要了,其實很多概念都是爲了兼容而遺留下來的,於是很多人就將它們當成教條,這很不應該。


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