文章目錄
- 摘要
- 柔性數組成員
- 基本使用
- 細節探究
- 零長度數組-定長數組-變長數組
摘要
本文先介紹柔性數組成員(flexible array member)的基本使用,然后介紹其內存結構。最后,補充了一些數組相關的其他概念。
柔性數組成員
基本使用
參考: 【C語言內功修煉】柔性數組的奧秘_數組_Albert Edison_InfoQ寫作社區
C99之后,可以使用 flexible array member。它大概長下面這個樣子。
struct buffer {unsigned int len;char contents[]; // flexible array member
};
- flexible array member 可以認為是零長度數組實現的一個特例(下文會介紹零長度數組)。
sizeof(buffer.contents)
的值為0。 - flexible array member 只能作為結構體的最后一個成員。
下面我們看一個demo,來體驗下 flexible array member 帶來的便利。
這個demo比較簡單。分配一個緩沖區,往里面寫內容。這個緩沖區保有緩沖區的大小。
// demo-1.c
#include <stdio.h>
#include <stdlib.h>struct buffer {unsigned int len;char contents[];
};int main(int argc, char *argv[]) {unsigned int buf_len = 100;// construct a bufferstruct buffer *buffer =malloc(sizeof(struct buffer) + buf_len * (sizeof(char)));buffer->len = buf_len;snprintf(buffer->contents, buffer->len, "%s", "hello world");printf("%s\n", buffer->contents);free(buffer);return 0;
}
如果不使用柔性數組,下面這樣,可以實現同樣的功能。而且也非常簡單。
//demo-2.c
#include <stdio.h>
#include <stdlib.h>struct buffer {unsigned int len;char *contents;
};int main(int argc, char *argv[]) {unsigned int buf_len = 100;// construct a bufferstruct buffer *buffer =malloc(sizeof(struct buffer) + buf_len * (sizeof(char)));buffer->contents = (char *)buffer + sizeof(struct buffer);buffer->len = buf_len;snprintf(buffer->contents, buffer->len, "%s", "hello world");printf("%s\n", buffer->contents);free(buffer);return 0;
}
這兩者有什么區別呢?下一節我們來探究下。
細節探究
參考:Zero Length (Using the GNU Compiler Collection (GCC))
首先,上面demo中,struct buffer
的大小是不同的。我這里直接給出大小。這個大小可以通過打印或者gdb方式獲取。
// 當前環境
Linux da1234cao 5.15.133.1-microsoft-standard-WSL2 x86_64 GNU/Linux// demo-2中buffer結構體
// sizeof(struct buffer) == 16 ; sizeof(char*) == 8
struct buffer {unsigned int len;char *contents;
};// demo-1中buffer結構體
// sizeof(struct buffer) == 4 ; sizeof(buffer.contents) == 0
struct buffer {unsigned int len;char contents[];
};// 修改下flexible array member的類型
// sizeof(struct buffer) == 8 ; sizeof(buffer.contents) == 0
struct buffer {unsigned int len;long contents[];
};
可以看到 flexible array member 的空間大小為0。但由于尾部填充,flexible array member 可能會導致結構體的空間變大,其空間對齊方式,與 flexible array member 的類型相同。我們知道指針是可以進行加法運算的,同樣,它的偏移量由 flexible array member 的類型決定。
此時,我們來繪制下包含 flexible array member 結構體的內存結構。
而上面demo-2.c中的結構體內存則是這樣。
最后,我不建議將一個包含 flexible array member 的結構體,嵌套到其他結構體中,雖然這樣做是允許的。如果你想這么做的話,請自行參考官方手冊。我沒太看懂這塊。
Tips: 如果結構體中包含 flexible array member , 可以放心的將結構體進行memset操作。flexible array member 總是指向后面的位置。
零長度數組-定長數組-變長數組
通過上一節,我們已經掌握了 flexible array member 的使用。這里補充些其他相關的基本概念。
零長度數組。
可以認為 flexible array member 是零長度數組的一種實現。 flexible array member 是在C99之后出現的。在C99之前,程序員們這樣使用零長度數組。
struct line {int length;char contents[0]; // [] 中多了一個0
};
上面的代碼和 flexible array member 效果相同。但是,在C99之后,請使用 flexible array member 。按照手冊寫代碼,我不知道有沒有什么原因或者好處。
定長數組。
在C99之前,數組在創建的時候,必須給定一個常量。這個數組長度在編譯的時候,已經確定。
// 定長數組
char array[10];// 下面這個也是定長數組
// 可以參考下 《C語言程序設計 -- 現代方法》8.1.2 數組初始化
// 如果給定了初始化式,可以省略掉數組的長度; 編譯器利用初始化式的長度來確定數組的大小。數組仍然有固定數量的元素;
char array[] = {'a', 'b', 'c'};
變長數組。
參考: Variable Length (Using the GNU Compiler Collection (GCC))
數組長度在運行時確定。
int n = 10;
char array[n];