430編程C語言常識(IAR)(二)結構體與聯合體

轉自:http://www.amobbs.com/thread-5465091-1-2.html

結構體與聯合體是C語言的常見數據類型,可對C的基本數據類型進行組合使之能表示複雜的數據結構,意義深遠,是優異代碼的必備工具。

一.        struct與 union的基本用法,在語法上union與struct相同,因此只以struct爲例
1.1        基本用法:
  1. struct AA{ int a; int b;}; //結構體的聲明和定義
  2. struct AA s1; //變量的聲明和定義 
  3. s1.a=3; //變量的使用:
複製代碼
1.2        在聲明結構體的同時定義變量:
  1. struct AA{int a; int b}s2={1, 2}; //此處AA爲可選項,初始化部分爲可選
  2. s2.a=5;                 //變量的使用
複製代碼
1.3        使用 typedef 來簡化struct的類型說明:
  1. typedef struct AA{int a; int b;}SAA; 
  2. SAA s3, s4;         //變量的聲明和定義
  3. s3.a=8; //變量的使用
複製代碼
1.4 使用時尤其注意後面的分號,必不可少;
二.        struct 與 union的區別
2.1 struct中的成員是按順序依次排列,互相獨立,在排列時引入了對齊問題(2.2);而union中的成員共用一塊內存,起始地址都是相同的,即union中的成員是對同一地址的多個引用、對同一地址的多種表達方法。
2.2 struct的對齊問題
對齊問題即struct中每個成員起始地址的分配。爲了可以快速訪問到每個成員,(以EW430爲例)編譯器根據成員的類型放到合適的地址上,默認爲2字節對齊。如:
Struct AA{char c; int d;}aa;
假設aa被分配在地址N上,並且N爲偶數,則aa.c的地址爲N,aa.d的地址爲N+2,而N+1地址未使用被浪費了。
對齊字節大小的指定:通過#pragma pack(n)來指定對齊字節的大小,n爲某些常量(EW430中可取1,2,4,8,16),指定以n字節對齊。通常使用編譯器默認的對齊大小最爲適宜。如果指定對齊大小爲1字節對齊,以上面的結構體變量aa爲例,aa.c地址爲N,aa.d地址爲N+1,是個奇數地址,因爲430在奇數地址只能讀取一個字節,因此要訪問d成員需要讀取兩次才能完成,後果是代碼變長、速度變慢。
三.        匿名結構體與聯合體
匿名結構體和聯合體,即沒有名字的結構體或者聯合體,這種結構體(或聯合體)無法通過.與->操作符引用(因爲它所屬的結構體或聯合體沒有名字,無法應用),而像暴露在外面一樣,與外層作用域相同,可直接使用。
3.1 C標準中提及的匿名結構體和聯合體(草稿原文引用)(C標準中提及的匿名結構(聯合)體應該只適用於有名結構體(聯合)中的匿名結構(聯合)體成員)
  1. struct v{
  2.         union{ //匿名聯合體
  3.                 struct {int i, j;}; //匿名結構體
  4.                 struct {long k, l;}w;
  5.         };
  6.         int m;
  7. }v1;
  8. v1.i=2; //合法,匿名結構體的成員被直接使用
  9. v1.k=3;//非法,有名字的結構體需要引用他的名字,如下
  10. v1.w.k=5; //合法
複製代碼
3.2 IAR中的匿名結構體和聯合體
IAR中的匿名結構體和聯合體可以具有全局作用域,因此結構體或聯合體中的成員可以作爲全局變量使用,但卻兼具結構體或者聯合體的屬性。
(1)        IO430.h系列頭文件的寄存器聲明方式:
如:
SFRIE1
  1. __no_init volatile union
  2. {
  3.   unsigned short SFRIE1;   /* Interrupt Enable 1 */

  4.   struct
  5.   {
  6.     unsigned short WDTIE           : 1; /* WDT Interrupt Enable */
  7.     unsigned short OFIE            : 1; /* Osc Fault Enable */
  8.     unsigned short                : 1;
  9.     unsigned short VMAIE           : 1; /* Vacant Memory Interrupt Enable */
  10.     unsigned short NMIIE           : 1; /* NMI Interrupt Enable */
  11.     unsigned short ACCVIE          : 1; /* Flash Access Violation Interrupt Enable */
  12.     unsigned short JMBINIE         : 1; /* JTAG Mail Box input Interrupt Enable */
  13.     unsigned short JMBOUTIE        : 1; /* JTAG Mail Box output Interrupt Enable */
  14.   }SFRIE1_bit;
  15. } @0x0100;
複製代碼
說明:[1].  SFRIE1和SFRIE1_bit具有全局變量的性質,可以直接被引用。
         [2].        SFRIE1和SFRIE1_bit在同一聯合體中,根據聯合體的性質,他們共享同一地址,即對同一寄存器不同訪問方式,SFRIE1對整個寄存器操作,SFRIE1_bit可對某位操作,如:
SFRIE1 |= 0x0001;和SFRIE1_bit.WDTIE = 1;具有相同效果。
         [3].        冒號(:)與整數稱之爲位域,使用位域表達的變量使用同一數據中的不同位,並按順序排列。整數表示這個變量佔用多少位。沒有名字的位域不能被引用到,一般用來保留未使用到的位(佔位作用)。
(2)  在應用程序中也可以使用此特性來實現一些功能。
記得某位網友曾提出過這樣的問題,要高效的使用一個整數的高8位和低8位,則可以用如下代碼解決:
  1. union {
  2.         unsigned int num;
  3.         struct {
  4.                 unsigned char nLow;
  5.                 unsigned char nHigh;
  6.         };
  7. };
複製代碼
或者
  1. union {
  2.         unsigned int num;
  3.         struct {
  4.                 unsigned int nLow        :8;
  5.                 unsigned int nHigh         :8;
  6.         };
  7. };
  8. int a = num;
  9. int b = nLow;
  10. int c = nHigh;
複製代碼
非常好的解決方案,只佔用一個整數的空間,可以對高8位、低8位、整個16位引用而不需要計算。

(3) 聯合體中的位域(補充)
  1. union {
  2.         unsigned int z;
  3.         unsigned int z1 : 1;
  4.         unsigned int z2 : 2;
  5.         unsigned int z3 : 3;
  6.         unsigned int z4 : 4;
  7. };
  8. z = 0xFFFF;
  9. a = z1;
  10. b = z2;
  11. c = z3;
複製代碼
結果:a = 1, b = 3, c = 7;

(4)結構體中的位域長度0 (補充)
  1. union ZZ{
  2.         unsigned int z1 : 1;
  3.         unsigned int z2 : 1;
  4.         unsigned int z3 : 1;
  5.         unsigned int z4 : 1;
  6.         unsigned int : 0;
  7.         unsigned int z6 : 1;
  8. }zz;
複製代碼
長度爲0的位域是通知編譯器不要在以前的單元上分配位域了,代表着一個單元的位域分配結束,這個長度爲0的位域不能有名字。以後的位域分配要新開闢一個單元。
以上的例子中,z1, z2, z3, z4共用一個unsigned int中的4個bit,z6單獨使用一個unsigned int; 此結構體共佔用兩個unsigned int空間
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章