Android源码中有一些经常会遇到的c++基础的内容,笔者对C++ 变长数组进行简单熟悉。

C++ 变长数组

在Android系统源码中,会经常出现变长数组,类似如下的结构

 1//bionic/libc/system_properties/include/prop_area.h
 2struct prop_bt {
 3  uint32_t namelen;
 4  atomic_uint_least32_t prop;
 5  atomic_uint_least32_t left;
 6  atomic_uint_least32_t right;
 7  atomic_uint_least32_t children;
 8  char name[0];
 9
10  prop_bt(const char* name, const uint32_t name_length) {
11    this->namelen = name_length;
12    memcpy(this->name, name, name_length);
13    this->name[name_length] = '\0';
14  }
15
16 private:
17  BIONIC_DISALLOW_COPY_AND_ASSIGN(prop_bt);
18};

可以看到除去namelen和几个原子操作的变量,最后是一个char name[0]的写法,这种写法就是变长数组的用法。

变长数组作用

变长数组又叫柔性数组。让数组长度是可变的,根据需要进行分配。方便操作,节省空间。不需要一开始定义,需要的时候再分配大小。

 1#include <iostream>
 2#include<string.h>
 3
 4typedef struct Data
 5{
 6    int namelen;
 7    char name[0];
 8}Data_t;
 9
10int main()
11{
12    char str[] = "IronMan";
13    int nLen = strlen(str);
14    printf("no malloc struct size (%u), nLen(%u) \n", sizeof(Data_t), nLen);
15
16    Data_t *myData = (Data_t*)malloc(sizeof(Data_t) + nLen);
17    myData->namelen = nLen;
18    memmove(myData->name, str, nLen + 1);
19    printf(" Data struct len(%d), name(%s) \n", myData->namelen, myData->name );
20
21    free(myData);
22    return 0;
23}

结果输出

结论:可以看到结构体的大小仅只有namelen的大小。分配完结构体的堆区之后,堆区的前4个字节是namelen,后面都是变长数组的内容。

进一步探讨

上述的name[0]也可以写成name[]同样不占用空间,且地址紧跟在结构后面。但是如果写成char *name,那么这样就会作为指针,占用4个字节,地址不在结构之后,整个结构体就包含指针的大小。 另外采用char *name需要进行二次分配,操作比较麻烦,很容易造成内存泄漏。而直接采用变长的数组,只需要分配一次,然后进行取值即可以。