天天看點

C語言中長度為0的數組

前面在看Xen的源碼時,遇到了一段代碼,如下所示:

​​

C語言中長度為0的數組

​​

注意上面最後一行的代碼,這裡定義了一個長度為的數組,這種用法可以嗎?為什麼可以使用長度為0 的數組?長度為的數組到底怎麼使用?……這篇文章主要針對該問題進行簡單的講解。廢話不多說了,現在就開始。

長度為的數組在标準c和c++中是不允許的,如果使用長度為的數組,編譯時會産生錯誤,提示數組長度不能為。但在GNUc中,這種用法卻是合法的。它的最典型的用法就是位于數組中的最後一項,如上面所示,這樣做主要是為了友善記憶體緩沖區的管理。如果你将上面的長度為的數組換為指針,那麼在配置設定記憶體時,需采用兩步:首先,需為結構體配置設定一塊記憶體空間;其次再為結構體中的成員變量配置設定記憶體空間。這樣兩次配置設定的記憶體是不連續的,需要分别對其進行管理。當使用長度為的數組時,則是采用一次配置設定的原則,一次性将所需的記憶體全部配置設定給它。相反,釋放時也是一樣的。

對于長度為的數組,在gcc手冊中,有如下一段代碼片段:

struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);
thisline->length = this_length;      

這段代碼的主要含義是定義了一個結構體,并對其進行初始化,上面結構體的第二個成員變量contents[0]事實上是不占記憶體空間的,是以整個結構體的長度sizeof(struct line)為4。當采用malloc為其申請記憶體空間時,如上所示,申請了一段長度為結構體長度加可變長度的記憶體空間給結構體類型的指針,這時contents就指向申請的可變長度的記憶體空間。由于是一次申請的,是以這段可變長度的記憶體空間和前面的結構體長度的記憶體空間是連續的。對于這段可變長度的記憶體空間,可以采用數組的方式對其進行通路。對于整個結構體,當不再使用時,可以使用free函數一次性對其進行釋放,而不必像指針那樣分别釋放。

下面舉例進行說明:

#include <stdio.h>
#include <stdlib.h>
#define LENGTH 10

struct test1
{
int a;
int *b;
}__attribute((packed));

struct test2
{
int a;
int b[0];
}__attribute((packed));

struct test3
{
int a;
int b[1];
}__attribute((packed));

int main()
{
struct test1 *var1;
struct test2 *var2;
struct test3 *var3;
int i;

printf("the length of struct test1:%d\n",sizeof(struct test1));
printf("the length of struct test2:%d\n",sizeof(struct test2));
printf("the length of struct test3:%d\n",sizeof(struct test3));

var1=(struct test1*)malloc(sizeof(struct test1));
var1->a=1;
var1->b=(int *)malloc(sizeof(int));
*var1->b=1;
printf("\nvar1->a=%d,*(var1->b)=%d\n",var1->a,*var1->b);

var2=(struct test2*)malloc(sizeof(struct test2)+sizeof(int)*LENGTH);
var2->a=2;
printf("\nvar2->a=%d\n",var2->a);
for(i=0;i<LENGTH;i++)
{
var2->b[i]=i;
printf("var2->b[i]=%d\t",var2->b[i]);
}
printf("\n\n"); 

var3=(struct test3*)malloc(sizeof(struct test3));
var3->a=3;
(var3->b)[0]=3;
printf("var3->a=%d,(var3->b)[0]=%d\n",var3->a,(var3->b)[0]);


free(var1->b);
free(var1);
free(var2);
free(var3);

}      

這段程式的運作結果如下圖所示:

​​

C語言中長度為0的數組

​​

從上面的結果可以看出:

l 長度為的數組并不占有記憶體空間,而指針方式需要占用記憶體空間。

l 對于長度為數組,在申請記憶體空間時,采用一次性配置設定的原則進行;對于包含指針的結構體,才申請空間時需分别進行,釋放時也需分别釋放。

l 對于長度為的數組的通路可采用數組方式進行。

前面在看Xen的源碼時,遇到了一段代碼,如下所示:

​​

C語言中長度為0的數組

​​

注意上面最後一行的代碼,這裡定義了一個長度為的數組,這種用法可以嗎?為什麼可以使用長度為0 的數組?長度為的數組到底怎麼使用?……這篇文章主要針對該問題進行簡單的講解。廢話不多說了,現在就開始。

長度為的數組在标準c和c++中是不允許的,如果使用長度為的數組,編譯時會産生錯誤,提示數組長度不能為。但在GNUc中,這種用法卻是合法的。它的最典型的用法就是位于數組中的最後一項,如上面所示,這樣做主要是為了友善記憶體緩沖區的管理。如果你将上面的長度為的數組換為指針,那麼在配置設定記憶體時,需采用兩步:首先,需為結構體配置設定一塊記憶體空間;其次再為結構體中的成員變量配置設定記憶體空間。這樣兩次配置設定的記憶體是不連續的,需要分别對其進行管理。當使用長度為的數組時,則是采用一次配置設定的原則,一次性将所需的記憶體全部配置設定給它。相反,釋放時也是一樣的。

對于長度為的數組,在gcc手冊中,有如下一段代碼片段:

struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);
thisline->length = this_length;      

這段代碼的主要含義是定義了一個結構體,并對其進行初始化,上面結構體的第二個成員變量contents[0]事實上是不占記憶體空間的,是以整個結構體的長度sizeof(struct line)為4。當采用malloc為其申請記憶體空間時,如上所示,申請了一段長度為結構體長度加可變長度的記憶體空間給結構體類型的指針,這時contents就指向申請的可變長度的記憶體空間。由于是一次申請的,是以這段可變長度的記憶體空間和前面的結構體長度的記憶體空間是連續的。對于這段可變長度的記憶體空間,可以采用數組的方式對其進行通路。對于整個結構體,當不再使用時,可以使用free函數一次性對其進行釋放,而不必像指針那樣分别釋放。

下面舉例進行說明:

#include <stdio.h>
#include <stdlib.h>
#define LENGTH 10

struct test1
{
int a;
int *b;
}__attribute((packed));

struct test2
{
int a;
int b[0];
}__attribute((packed));

struct test3
{
int a;
int b[1];
}__attribute((packed));

int main()
{
struct test1 *var1;
struct test2 *var2;
struct test3 *var3;
int i;

printf("the length of struct test1:%d\n",sizeof(struct test1));
printf("the length of struct test2:%d\n",sizeof(struct test2));
printf("the length of struct test3:%d\n",sizeof(struct test3));

var1=(struct test1*)malloc(sizeof(struct test1));
var1->a=1;
var1->b=(int *)malloc(sizeof(int));
*var1->b=1;
printf("\nvar1->a=%d,*(var1->b)=%d\n",var1->a,*var1->b);

var2=(struct test2*)malloc(sizeof(struct test2)+sizeof(int)*LENGTH);
var2->a=2;
printf("\nvar2->a=%d\n",var2->a);
for(i=0;i<LENGTH;i++)
{
var2->b[i]=i;
printf("var2->b[i]=%d\t",var2->b[i]);
}
printf("\n\n"); 

var3=(struct test3*)malloc(sizeof(struct test3));
var3->a=3;
(var3->b)[0]=3;
printf("var3->a=%d,(var3->b)[0]=%d\n",var3->a,(var3->b)[0]);


free(var1->b);
free(var1);
free(var2);
free(var3);

}      

這段程式的運作結果如下圖所示:

​​

C語言中長度為0的數組

​​

從上面的結果可以看出: