通过过度分配内存在结构中内联可变长度数组是否有效?

Is it valid to inline variable length arrays in structs by over-allocating memory?

我有一个结构,我想保留在连续的内存中,这样我就可以 memcpy 整个结构等。但是我的结构包含一个可变长度的数组。 现在这个长度将在程序执行期间固定,但在编译时它是未知的。我可以通过过度分配来解决这个问题吗内存跟随结构为数组腾出空间?

所以如果我从

开始
struct license_plate{
    char issuing_province_territory_code [2];
    char* number;
}

我需要一个单独的 malloc 作为 number 所以我想做以下事情

struct license_plate_v2 {
    char issuing_province_territory_code [3];
    char number[1];
}

并这样分配它

size_t sizeof_license_plate_v2( int number_length ){
    return sizeof(struct license_plate_v2) + number_length * sizeof(char);
}


struct license_plate_v2* malloc_license_plate_v2( int number_length ){
    return malloc( sizeof_license_plate_v2( number_length ) );
}

然后能够像

一样遍历​​数组
struct license_plate_v2* index_license_plate_v2( struct license_plate_v2 *arr, int index, int plate_num_len ){
    return  arr + index * sizeof_license_plate_v2(plate_num_len);
}

void print_all( struct license_plate_v2* plates, int num_of_plates, int plate_num_len ){
    for( int plate_index = 0; plate_index < num_of_plates; plate_index++ ){
        struct license_plate_v2* plate = index_license_plate_v2( plates, plate_index, plate_num_len );
        printf( "where: %s, plate: %s\n", plate->issuing_province_territory_code, plate->number  );
    }
}

这是有效的 C 语言吗?这保证有效还是我使用未定义的行为?如果数组是结构体,字节对齐有什么问题吗?有这个术语吗?这是实现这种效果的正确方法吗?

似乎可行:

#include <stdlib.h>

int main( int argc, char** argv ) {
    //these values could have from from argv for example
    int num_len = 7;


    struct license_plate_v2 *arr = malloc( 4  * sizeof_license_plate_v2(num_len) );

    struct license_plate_v2 *arr_0 = arr + 0 * sizeof_license_plate_v2(num_len);
    memcpy( arr_0->issuing_province_territory_code, "ON"      , 3           * sizeof(char) );
    memcpy( arr_0->number                         , "BFKK281" , (num_len+1) * sizeof(char) );

    struct license_plate_v2 *arr_1 = arr + 1 * sizeof_license_plate_v2(num_len);
    memcpy( arr_1->issuing_province_territory_code, "ON"      , 3           * sizeof(char) );
    memcpy( arr_1->number                         , "BYTR741" , (num_len+1) * sizeof(char) );

    struct license_plate_v2 *arr_2 = arr + 2 * sizeof_license_plate_v2(num_len);
    memcpy( arr_2->issuing_province_territory_code, "ON"      , 3           * sizeof(char) );
    memcpy( arr_2->number                         , "CAAA224" , (num_len+1) * sizeof(char) );

    struct license_plate_v2 *arr_3 = arr + 3 * sizeof_license_plate_v2(num_len);
    memcpy( arr_3->issuing_province_territory_code, "ON"      , 3           * sizeof(char) );
    memcpy( arr_3->number                         , "CASD431" , (num_len+1) * sizeof(char) );

    print_all( arr, 4, 7 );

    free( arr );   
}

PS- 这是一个说明问题的简化示例,现实世界的问题涉及多达数百万个位置和数千个(运行 但不是编译时间常数)的数据点每个都是结构而不是 char,因此一些明显的解决方法不适用。

具有灵活数组成员的结构不能是数组的元素。这是在 C standard:

的第 6.7.2.1p3 节中规定的

A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array

原因是数组索引是通过指向一个内存位置来完成的,该内存位置是结构大小的倍数。但是,如果结构的大小可变,则无法知道结构的下一个实例在内存中的位置。

在您的特定情况下,车牌号的最大长度并没有那么大,因此只需使用足够大的固定大小来容纳它可能包含的任何值。

struct license_plate{
    char issuing_province_territory_code[3];
    char number[20];
}

此外,使用大小为 1 的数组设置灵活数组成员的方法是标准化之前的旧方法,通常称为 "the struct hack"。声明灵活数组成员的现代方法是使用未指定的大小:

struct license_plate_v2 {
    char issuing_province_territory_code [3];
    char number[];
}

sizeof(struct license_plate_v2)不包括flexible array member