【问题标题】:how to copy to array inside struct?如何复制到结构内的数组?
【发布时间】:2021-05-04 07:56:18
【问题描述】:

如何在c中的struct内部复制到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 成员(通过使用其地址而不是 @ 987654332@),导致stack smashing detected。但是为什么它以这种错误的方式实现?(所以我也想知道引入灵活数组的原理)

【问题讨论】:

  • 可能我不明白你的问题是什么,但我对你的两个例子都没有问题。但是我在C 中编译时重现了第二个错误,但它在C++ 中编译并成功执行
  • 如果你的结构只有一个成员 - 不完整的数组(例如 int ar[]char ar[]),你的 c++ 会编译吗?如果是这样,那么cc++ 之间存在差异,因为c 中的flexible array member in a struct with no named members 错误不会编译(可能是数组中缺少维度而没有在括号中定义其长度,但我怀疑在c++ 数组衰减到已知长度为 8 字节的指针)
  • 如果上述方法适用于 C++ 别担心 - 它适用于 C 或 C++。您通过尝试将信息复制到 f.buf 来调用未定义的行为,而它还没有分配任何内存。仅仅因为您没有观察未定义行为的故障并不意味着它可以正常工作。
  • "incomplete type is not allowed" 搜索该错误消息(尽管修复拼写)并阅读您找到的一些内容以了解其含义。
  • @AndrewHenle 是对的,但它可以在 C++ 中工作,因为 MS VisualStudio 编译器不使用标准,而是有自己的规则。

标签: c++ arrays c struct sizeof


【解决方案1】:

当您在 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);
}`

【讨论】:

    【解决方案2】:

    让我们在这里使用 intel/amd 架构,其中 char => 1 byte 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 个字节),因为它根本不知道要分配多少。

    编辑: 离开我的电脑,同时弹出了其他答案。另一个答案很好!!!但我希望这可以帮助您了解发生了什么。

    【讨论】:

      【解决方案3】:

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

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

      您还可以对flexible array members in C here 的用法进行澄清

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-06
        • 2012-03-17
        • 1970-01-01
        • 1970-01-01
        • 2016-03-31
        • 2016-03-31
        • 2012-07-22
        • 1970-01-01
        相关资源
        最近更新 更多