本人就職于國際知名終端廠商,負責modem芯片研發,
在5G早期負責終端資料業務層、核心網相關的開發作業,目前牽頭6G算力網路技術標準研究,
博客內容主要圍繞:
5G協議講解
算力網路講解(云計算,邊緣計算,端計算)
高級C語言講解
Rust語言講解
文章目錄
- C99伸縮型資料成員
- 一、宣告一個伸縮型陣列成員
- 二、伸縮型陣列成員的限制
- 三、伸縮型陣列成員與指標的區別
- 四、ISO C99伸縮型陣列成員 與 GCC中的零長度陣列的區別
- GCC中的擴展
C99伸縮型資料成員
C99新增一個特性:伸縮型陣列成員(Flexible array member),利用這項新特性宣告的結構,其最后一個陣列成員具有下述特性:
- 該陣列不會立即存在(不占用記憶體);
- 使用這個伸縮型陣列成員可以撰寫合適的code,就好像它確實存在并具有需要數目的元素一樣,
一、宣告一個伸縮型陣列成員
首先看一個伸縮型陣列成員的例子:
struct flex
{
int count;
double average;
double scores[]; //伸縮型資料成員
};
宣告一個伸縮型陣列成員有如下規則:
- 伸縮型陣列成員必須是結構的最后一個成員;
- 結構中必須至少有一個成員;
- 伸縮陣列的宣告類似于普通陣列,只是它的方括號中是空的,
宣告一個struct flex 型別的結構變數時,不能用scores做任何事情,因為沒有給這個陣列預留存盤空間,所以我們需要通過malloc等類似函式給scores陣列分配記憶體,看下面的例子:
#include<stdio.h>
#include<stdlib.h>
#define COURSES_NUM 3
#pragma pack(4)
struct flex
{
int count;
double average;
double scores[]; //伸縮型陣列成員
};
int main()
{
//編譯器并沒有給 scores 陣列分配記憶體
printf("struct flex size %zd\n",sizeof(struct flex));
//請求為一個結構和一個陣列分配存盤空間
struct flex * person = malloc(sizeof(struct flex) + COURSES_NUM*sizeof(double));
person->count = COURSES_NUM;
person->scores[0]=95.;
person->scores[1]=100.;
person->scores[2]=80.;
person->average = (person->scores[0]+person->scores[1]+person->scores[2])/3.;
printf("person average is %lf\n",person->average);
free(person);
return 0;
}
輸出如下圖:

我們看到 sizeof(struct flex) == 12,說明編譯器并沒有給scores陣列預留記憶體空間,
二、伸縮型陣列成員的限制
第一,不能用結構體進行賦值和拷貝,例如下面的code是錯誤的:
struct flex *person1 , *person2; // *person1 , *person2都是結構
......
*person1 = *person2; //錯誤
這樣做只能拷貝除伸縮型陣列成員之外的其它成員,如果確定要拷貝,應該使用類似memcpy()的函式操作,
第二,不要以按值方式把這種結構傳遞給函式,原因相同,按值傳遞一個引數與賦值類似,要把結構的地址傳遞給函式,
第三,不要使用帶伸縮型陣列成員的結構作為陣列成員或另一個結構的成員,
三、伸縮型陣列成員與指標的區別
區別一:編譯器為結構預留的記憶體大小不同,看下面的例子:
#include<stdio.h>
#include<stdlib.h>
#define COURSES_NUM 3
#pragma pack(4)
struct flex
{
int count;
double average;
double scores[]; //伸縮型陣列成員
};
struct pointer
{
int count;
double average;
double *scores; //指標資料成員
};
int main()
{
//編譯器并沒有給 scores 陣列分配記憶體
printf("struct flex size %zd\n",sizeof(struct flex));
//編譯器給 scores 指標分配記憶體
printf("struct pointer size %zd\n",sizeof(struct pointer));
return 0;
}
結果輸出如下:

博主使用的是64位作業系統,所以指標占用了8B存盤空間,然而伸縮型陣列在宣告時并未占用存盤空間,
區別二:成員地址分配不同,看下圖解釋:

上圖應該解釋的很清楚了,伸縮型陣列成員中存盤的資料與其在結構中緊鄰的上一個成員存盤的資料在記憶體的邏輯地址上是連續的,而指標資料成員中存盤的存放資料的邏輯地址,不一定與其結構中緊鄰的上一個成員存盤的資料在記憶體邏輯地址上連續,
這也是為什么不建議使用帶伸縮型陣列成員的結構作為陣列成員或另一個結構的成員,
看下面的Demo code:
#include<stdio.h>
#include<stdlib.h>
#define COURSES_NUM 3
#pragma pack(4)
struct flex
{
int count;
double average;
double scores[]; //伸縮型資料成員
};
struct pointer
{
int count;
double average;
double *scores; //資料成員
};
int main()
{
struct flex * person_flex = malloc(sizeof(struct flex)+COURSES_NUM*sizeof(double));
struct pointer * person_pointer = malloc(sizeof(struct pointer));
person_pointer->scores = malloc(COURSES_NUM*sizeof(double));
printf("[person_flex] average address is %p , scores address is %p\n",
&person_flex->average,person_flex->scores);
printf("[person_pointer] average address is %p , scores address is %p\n",
&person_pointer->average,person_pointer->scores);
free(person_flex);
free(person_pointer->scores);
free(person_pointer);
return 0;
}
輸出結果如下:

這里的對比并不是說誰好誰壞,好與壞取決于專案中的具體應用!
四、ISO C99伸縮型陣列成員 與 GCC中的零長度陣列的區別
其實本質還是相同的,只不過在GCC中的宣告語法如下:
struct line {
int length;
char contents[0]; // Zero-length array
};
struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
GCC中的擴展
GCC中允許對伸縮型陣列成員靜態初始化,這個程序等價于定義了一個新的結構體,包含原始的資料成員以及足夠容納初始陣列物件的陣列,看下面的code:
struct f1 {
int x;
int y[];
} f1 = { 1, { 2, 3, 4 } };
//等價于定義一個新結構體
struct f1 {
int x;
int y[3];
};
GCC中允許有伸縮型陣列物件的結構,內嵌在其它結構或聯合中,對于這類結構的初始化有一些限制:
- 只允許對頂層的結構進行非空初始化(Non-empty initialization)
- 如果是非頂層成員,只能進行空初始化
看下面的code:
struct f1 {
int x;
int y[3];
};
struct f2 {
struct f1 f1; int data[3];
};
/*
有效,非頂層空初始化
{ 2, 3, 4 }初始化陣列data
而data的邏輯地址與f1結構中的y相同,等價于靜態初始化了f1結構中的伸縮型陣列y
*/
struct f2 _f2 = { { 1 }, { 2, 3, 4 } }
struct foo { int x; int y[]; };
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; //頂層所以有效
struct bar b = { { 1, { 2, 3, 4 } } }; //非頂層所以無效
struct bar c = { { 1, { } } }; //非頂層空初始化,有效
struct foo d[1] = { { 1, { 2, 3, 4 } } }; //非頂層非空初始化,無效

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/286436.html
標籤:其他
