如何复制到结构内的数组?

问题描述

c 中如何复制到结构体内部的 flexible array

    #include <stdio.h>
    #include <string.h>
    
    typedef struct
    {
        int val;
        char buf[];
    } foo;
    
    int main()
    {
        foo f;
        f.val = 4;
        // f.buf = "asd"; -> invalid use of flexible array member
        memcpy(f.buf,"asd\0",4);
        printf("%s\n",f.buf);
    }

输出

    asd
    *** stack smashing detected ***: terminated
    Aborted (core dumped)

另外,如果结构体被声明为:

    typedef struct
    {
        char buf[];
    } foo

vscode 编辑器报错:

    incomplete type is not allow

和 gcc 给出错误

    error: flexible array member in a struct with no named members
        6 |     char buf[];

为什么现在允许结构体中的数组而指针是? (char *buf)。

另外,如果一个结构体有一个灵活的数组,它的sizeof(struct containsFlexArray)是什么?当它没有维度时,如何动态解析它的数组?

编辑: 如果上述在 C++ 中有效,因为不完整的数组“衰减”到已知长度的指针(x64 中的 8 个字节),为什么 c 中不是这种情况?如果我查看 asm,我会看到程序没有为结构分配足够的堆栈(它只为 foo.val member,but not bur foo.buf member 分配空间,在这种情况下,程序尝试使用覆盖 foo.val 成员(通过使用其address 而不是 foo.buf),这会导致 stack smashing detected。但为什么它以这种错误的方式实现?(所以我也想知道引入灵活数组背后的基本原理)

解决方法

您可能想阅读有关 flexible array member here 的信息。

看起来,当在 flexible array 中使用 struct 时,必须至少有一个其他数据成员,并且灵活数组成员必须在最后。

此外,您可能对 flexible array members in C here

的用法有一些说明 ,

当您在 main() 中声明一个实例时,您没有初始化 buf[] 数组。编译器不知道要分配多少内存。堆栈粉碎是一种编译器功能,可防止您的程序对您的计算机做……坏事。在 typedef 结构中向数组声明中添加一个数字。 像这样: ` #include #include

typedef struct
{
    int val;
    char buf[5];
} foo;

int main()
{
    foo f;
    f.val = 4;
    // f.buf = "asd"; -> invalid use of flexible array member
    memcpy(f.buf,"asd\0",4);
    printf("%s\n",f.buf);
}`
,

让我们在这里使用 intel/amd 架构,其中 char => 1 字节 int => 4,long 为 8 字节长。

结构对齐在这里是一个问题。您会看到,当您在 c 中声明一个结构体时,编译器会将其视为单个块。因此,如果您有这样的结构:

struct a {
   long l;
   char c1;
   char c2;
}

编译器查看使用的第一种类型,并为 l 分配 8 个字节的内存,查看 c 并确定 c1 比 l 短,而不是弄清楚 c1 的类型是什么,它为 c1 分配了 8 个字节的数据。它对 c2 也一样。所以你最终得到了 24 个字节长的结构,并且只使用了 10 个。如果你使用这个:

struct b {
  char c1;
  long l;
  char c2;
}

这将为 c1 分配 1 个字节,为 l 分配 8 个字节,为 c2 分配 8 个字节。所以你最终使用了 17 个字节和 10 个字节。好像你有这个:

struct b {
  char c1;
  char c2;
  long l;
}

好吧,它为 c1 分配了 1 个字节,为 c2 分配了 1 个字节,为 l 分配了 8 个字节。总共 10 个字节,但全部使用了 10 个。

那么它和数组有什么关系呢?你看看你有没有:

struct aa {
   char a;
   long b[];
}

这将知道最初为 b 分配至少一个字节。当你没有 char a,

struct aa {
   long b[];
}

编译器可能不分配任何内存(分配 0 个字节),因为它根本不知道要分配多少。

编辑: 离开我的电脑,同时弹出了其他答案。另一个答案很好!!!但我希望这有助于您了解正在发生的事情。