程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C 語言變長數組 struct 中 char data[0] 的用法

C 語言變長數組 struct 中 char data[0] 的用法

編輯:關於C語言

C 語言變長數組 struct 中 char data[0] 的用法


 

1、結構體內存布局(padding)

 

為了讓CPU能夠更舒服地訪問到變量,struct中的各成員變量的存儲地址有一套對齊的機制。這個機制概括起來有兩點:第一,每個成員變量的首地址,必須是它的類型的對齊值的整數倍,如果不滿足,它與前一個成員變量之間要填充(padding)一些無意義的字節來滿足;第二,整個struct的大小,必須是該struct中所有成員的類型中對齊值最大者的整數倍,如果不滿足,在最後一個成員後面填充。

The following typical alignments are valid for compilers from Microsoft, Borland, and GNU when compiling for 32-bit x86:

  • A char (one byte) will be 1-byte aligned.
  • A short (two bytes) will be 2-byte aligned.
  • An int (four bytes) will be 4-byte aligned.
  • A float (four bytes) will be 4-byte aligned.
  • A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux.
  • A long double (twelve bytes) will be 4-byte aligned on Linux.
  • Any pointer (four bytes) will be 4-byte aligned on Linux. (eg: char*, int*)

    The only notable difference in alignment for a 64-bit linux system when compared to a 32 bit is:

    • A double (eight bytes) will be 8-byte aligned.
    • A long double (Sixteen bytes) will be 16-byte aligned.
    • Any pointer (eight bytes) will be 8-byte aligned.

       

      #include 
      #include 
      #include 
      
        struct s1
              {
                      char ch,*ptr;
                      union
                      {
                              short a,b;
                              unsigned int c:2,d:1;
                      };
                      struct s1 *next;
              };
      
      int main()
      {
            
              printf("%d\n",sizeof(struct s1));
              return 0;
      }

      struct s1
      {
      char ch,*ptr; //ch和*ptr各占2bit,共4bit
      union //按照最長的計算,union占4bit
      {
      short a,b;
      unsigned int c:2,d:1;
      }
      struct *next; //指向struct的指針,和struct占相同的字節,8bit
      }

       

      2、變長數組

      摘要:在實際的編程中,我們經常需要使用變長數組,但是C語言並不支持變長的數組。此時,我們可以使用結構體的方法實現C語言變長數組。

      struct MyData
      /{
      / int nLen;
      / char data[0];
      /};

      在結構中,data是一個數組名;但該數組沒有元素;該數組的真實地址緊隨結構體MyData之後,而這個地址就是結構體後面數據的地址(如果給這個結構體分配的內容大於這個結構體實際大小,後面多余的部分就是這個data的內容);這種聲明方法可以巧妙的實現C語言裡的數組擴展。
      實際用時采取這樣:
      struct MyData *p = (struct MyData *)malloc(sizeof(struct MyData )+strlen(str))
      這樣就可以通過p->data 來操作這個str。

       

      這樣就可以通過p->data 來操作這個str。

       

      程序實例:


      /struct MyData
      /{
      / int nLen;
      / char data[0];
      /};
      /
      /int main()
      /{
      / int nLen = 10;
      / char str[10] = "123456789";
      /
      / cout << "Size of MyData: " < /
      / MyData *myData = (MyData*)malloc(sizeof(MyData) +10);
      / memcpy(myData->data, str, 10);
      /
      / cout << "myData's Data is: " << myData->data << endl;
      /
      / free(myData);
      /
      / return 0;
      /}

      輸出:

      /Size of MyData:
      4
      /myData"s Data is: 123456789

      以下是摘自:http://bbs.chinaunix.net/thread-1455677-1-1.html

      我想舉一個自己最近在項目中犯的錯誤來說明要踏踏實實做人,不要做裝B青年 \
      在代碼中,我需要在一個library和一個daemon之間通過socket傳送數據包,包的格式定義如下(為了簡化,我就用最簡單的數據類型舉例):

      1. typedef struct {
      2. int head;
      3. int size; //指明整個包的長度
      4. char reply;
      5. char data[0];
      6. } packet;
      7.  
      8. packet* cmd = malloc (sizeof(packet) + 20);
      9. memcpy (packet->data, some_data, 20); 復制代碼

        daemon將上面分配的cmd包發送給library,library接收到包後,需要將data字段中的數據取出來。size指明了整個包的長度,但沒有字段指明數據的長度。我需要這麼一個指明數據長度的字段嗎?作為一個裝B青年,我認為當然不需要,於是我這樣來計算數據的長度:

         

         

        1. #define offsetof(type, element) ((int)&((type *)0)->element)
        2. static inline size_t packet_data_len(packet* cmd) {
        3. assert(cmd);
        4. return cmd->size - offsetof(packet, data);
        5. }
        6.  
        7. memcpy (buffer_to_receive_data, cmd->data, packet_data_len (cmd)); 復制代碼

          於是乎,這段程序成功的給我帶來了無數的bug,莫名奇妙的segfault,奇怪的數據錯誤,還是有部分時間的正常工作。當然,最終我還是找到了問題:
          sizeof (packet) == 12;
          這是合理的,char reply被padding成了4個字節,而char data[0]字節為0。
          但,offsetof(packet, data) == 9,在計算偏移時,char reply為一個字節,沒有padding。
          所以packet_data_len每次都會返回比真實的數據多3個字節 ……

          最後我還是老老實實加了個data_len字段指明數據的長度。

           

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved