bloggerads

2014年9月26日 星期五

C 結構(structure) 的一些注意事項 (C89 / C99 / 對齊,Alignment)

1. 結構變數初值給定

首先,先宣告一個結構型態, 接下來再介紹兩種初值給定方法(C99/C89):
+  struct test
+  {
+    const char* cap;
+    unsigned char data_0;
+    int data_1;  
+  };

support C99 mode (現在新版本的GCC都有support C99 mode 的結構變數初值給定方法。 這種方法的優點是未來如果結構調整變數的位置,宣告變數初值不用跟著調整):

+  struct test node = 
+  {
+      .cap="first", 
+      .data_0=10,
+      .data_1=5
+  };

以下是傳統(C89 mode)的寫法 (很可惜的是目前Watcom C版本(1.9)尚未支援C99 mode結構變數的初值給定方法),所以還是用舊有的寫法:

+  struct test node = 
+ {
+      "first",   // cap
+      10,       // data_0
+      5          // data_1
+  };

2. 結構內變數對齊(alignment)的問題

寫程式的技巧常會將結構直接位址對應到某塊MMIO/Memory上,如果編譯時沒特別宣告,那麼結構裡面變數的變數位址會對齊到"最大變數的size"造成讀錯位址,範例如下



+  #include <stdio.h>
+  
+  struct test
+  {
+    unsigned int cap_0;
+    unsigned char data_0;
+    unsigned int cap_1;
+    unsigned char data_1;  
+  };
+  
+  int main()
+  {
+  
+      struct test node;
+  
+      printf("node size: %d\n", sizeof(node));
+      printf("node.cap_0 address : 0x%X\n", &(node.cap_0));
+      printf("node.data_0 address: 0x%X\n", &(node.data_0));
+      printf("node.cap_1 address : 0x%X\n", &(node.cap_1));
+      printf("node.data_1 address: 0x%X\n", &(node.data_1));
+      return 0;
+  }

應該要加上#pragma pack()這個前置處理,參考如下

+  #include <stdio.h>
+  
+  //#pragma pack(push)  // 先將原本的對齊方式暫存
+  //#pragma pack(1)   // 設定1個Byte為單位對齊
+  #pragma pack(push, 1)
+  struct test
+  {
+    unsigned int cap_0;
+    unsigned char data_0;
+    unsigned int cap_1;
+    unsigned char data_1;  
+  };
+  #pragma pack(pop)  // 回復原本對齊方式
+  
+  int main()
+  {
+  
+      struct test node;
+  
+      printf("node size: %d\n", sizeof(node));
+      printf("node.cap_0 address : 0x%X\n", &(node.cap_0));
+      printf("node.data_0 address: 0x%X\n", &(node.data_0));
+      printf("node.cap_1 address : 0x%X\n", &(node.cap_1));
+      printf("node.data_1 address: 0x%X\n", &(node.data_1));
+      return 0;
+  }



沒有留言:

張貼留言