c++ array of ZERO length

警告
本文最后更新于 2023-10-20,文中内容可能已过时。

old-style:[0]

我在查看代码的时候,发现有一个 struct长度为0 的数组。

1
2
3
4
5
struct data_t
{
    size_t size;
    int data[0];
};

如果打印出上面结构体,发现长度正好为 size_t,其中的 data 是不占用内存的。

1
2
3
4
5
cout << "sizeof(size_t):" << sizeof(size_t) << endl;
cout << "sizeof(data_t):" << sizeof(data_t) << endl;

//sizeof(size_t):8
//sizeof(data_t):8

原来,这样做的目的,是为了可以添加不限长度的数组,通过 malloc 分配内存大小,从而实现在代码中灵活分配数据的目的。

1
2
3
4
5
6
7
data_t* get_data(size_t size)
{
    data_t* d = (data_t*) malloc(sizeof(data_t) + size * sizeof(int));
    if (d)
        d->size = size;
    return d;
}

new-style:[]

其实,这是一种比较古老的写法,我们完全可以使用 arr[] (flexible array member) 来替代

1
2
3
4
5
6
struct data_t
{
    size_t size;
    //In C99 standard this is not neccessary as it supports the arr[] syntax.
    int data[];
};

完整的测试代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;

struct data_t
{
    size_t size;
    //This is an old C hack to allow a flexible sized arrays.
    int data[0];
    //In C99 standard this is not neccessary as it supports the arr[] syntax.
    //int data[];
};

data_t* get_data(size_t size)
{
    data_t* d = (data_t*) malloc(sizeof(data_t) + size * sizeof(int));
    if (d) d->size = size;
    return d;
}

int main()
{
    cout << "sizeof(size_t):" << sizeof(size_t) << endl;
    cout << "sizeof(data_t):" << sizeof(data_t) << endl;

    auto x = get_data(10);
    for (size_t i = 0; i < x->size; ++i)
        x->data[i] = i*i;

    for (size_t i = 0; i < x->size; ++i)
        cout << "x[" << i << "]:" << x->data[i] << endl;

    return 0;
}

best-style:[1]

上面的做法有一个问题,如果使用编译器选项 -pedantic 会有报错提示:

1
2
3
4
5
6
7
8
9
## 对于 int data[0]
main.cpp:11:14: warning: ISO C++ forbids zero-size array ‘data’ [-Wpedantic]
   11 |     int data[0];
      |              ^

## 对于 int data[]
main.cpp:13:9: warning: ISO C++ forbids flexible array member ‘data’ [-Wpedantic]
   13 |     int data[];
      |         ^~~~

It’s worth pointing out IMO the best way to do the size calculation, which is used in the Raymond Chen article linked above.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
struct data_t
{
    size_t size;
    int data[1];
};

data_t* get_data(size_t size)
{
    // 使用 offsetof 计算出 data[size] 占用的大小
    data_t* d = (data_t*) malloc(offsetof(data_t, data[size]));
    if (d) d->size = size;
    return d;
}

完整的测试代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <cstddef>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;

struct data_t
{
    size_t size;
    int data[1];
};

data_t* get_data(size_t size)
{
    data_t* d = (data_t*) malloc(offsetof(data_t, data[size]));
    if (d) d->size = size;
    return d;
}

int main()
{
    cout << "sizeof(size_t):" << sizeof(size_t) << endl;
    cout << "sizeof(data_t):" << sizeof(data_t) << endl;

    auto x = get_data(20);
    for (size_t i = 0; i < x->size; ++i)
        x->data[i] = i*i;

    cout << "x.size:" << x->size << endl;
    for (size_t i = 0; i < x->size; ++i)
        cout << "x[" << i << "]:" << x->data[i] << endl;

    return 0;
}

Ref:

相关内容

william 支付宝支付宝
william 微信微信
0%