微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

延迟指向具有灵活数组成员的结构的指针不会“复制”FAM?

如何解决延迟指向具有灵活数组成员的结构的指针不会“复制”FAM?

使用灵活数组成员 (FAM) 将 pointer 推迟到 struct 不会“复制”FAM?

根据这个程序,这似乎是行为,它使用 FAM 创建结构的实例,然后检查指向结构的指针和结构的取消引用的“二进制布局”。

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(){

typedef struct{
  uint8_t  idim;
  uint32_t data[];
}array_t;  // https://gustedt.wordpress.com/2011/03/14/flexible-array-member/

  int64_t  x_bdim = sizeof(array_t) + sizeof(uint32_t)*0x2;
  array_t* _x     = aligned_alloc(0x1000,x_bdim);
  array_t   x     = *_x;
  uint8_t* raw;

  x.idim          = 0xff;
  x.data[0x0]     = 0x11111111;
  x.data[0x1]     = 0x22222222;

  _x->idim          = 0xff;
  _x->data[0x0]     = 0x11111111;
  _x->data[0x1]     = 0x22222222;

  printf("%'ld %'ld %'ld\n",sizeof(array_t),sizeof(array_t) + sizeof(uint32_t)*0x2,x_bdim);

  putchar(0x0a);
  raw = (uint8_t*)_x;
  for(int i=0; i<x_bdim; ++i)
    printf("%02x\n",raw[i]);

  putchar(0x0a);
  for(int i=0; i<0x2; ++i)
    printf("%08x\n",_x->data[i]);

  putchar(0x0a);
  raw = (uint8_t*)&x;
  for(int i=0; i<x_bdim; ++i)
    printf("%02x\n",x.data[i]);
}

我是否遗漏了什么,或者这是正确的吗?我们不应该尊重(指向)具有灵活数组成员的结构的故事的士气,因为我们只获得结构的“头”而不是完整的数组数据?

解决方法

有点技术性 - 在这里取消引用指针是用词不当。实际问题是关于使用 FAM 复制结构。

您的观察是正确的,如果您尝试使用 FMA 复制结构体,则不会复制 FMA 部分。原因很简单——由于编译器不知道分配的存储空间的大小,因此无法复制 FMA“尾部”。

,

那是正确的。编译器不知道数组的大小,并假设此类操作为 0,包括复制、返回、分配和比较。实际上,灵活数组在结构体之后。

GCC 的原型语法更明显。他们把它写成uint32_t data[0];

,

C 2018 6.7.2.1 18 说:

…在大多数情况下,灵活的数组成员被忽略…

并且 C 标准中没有说在使用结构时使用灵活的数组成员(是值的一部分),如 array_t x = *_x;。所以在这个初始化中数组成员没有被复制的事实是因为标准中没有说它被复制。

该标准还提到了两个关于灵活数组成员的值得注意的事情。下一句允许填充以满足灵活数组成员的对齐要求:

特别是,结构的大小就像省略了灵活的数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。

之后的句子表示访问该成员(如使用 x->data)的行为就像那里确实存在一个数组,其大小与为其提供的内存一样大。

因此最后一句允许您手动访问灵活数组成员中的数据,但第一句不需要编译器自动对它们执行任何操作。

这样做的原因当然是编译器一般无法知道灵活数组成员的大小。其他答案(到目前为止)错误地说明了这一点;他们说编译器知道大小。在显示的代码中,编译器当然可以看到大小,因此它的知识不足不是灵活数组成员未被复制的原因。更准确地说,原因是编译器无法知道所有使用结构体的情况下的大小,因为内存预留可能在当前正在编译的代码之外,所以一般规则是不处理灵活数组成员作为基本结构的一部分,即使内存预留可见。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。