繁体   English   中英

malloc 的这种使用会导致“可选”结构字段吗?

[英]Could this use of malloc lead to an “optional” struct field?

我正在实现一个结构,我需要(在运行时)有一个可选字段。
所以我想到了这个:

//...
#include <stdlib.h>

struct test {
  int x;  // Must be
  int y;  // Optional (Must be the last field..(?))
};

int main(int argc, char **argv) {
    // With the optional field
    struct test *a = malloc(sizeof(*a));
    a->x = 11;
    a->y = 55;
    
    // Without the optional field
    struct test *b = malloc(sizeof(*b) - sizeof(int));
    b->x = 22;
    
    // ...
    
    free(a);
    free(b);
    return 0;
}

这段代码可以按我的要求做吗?
可能添加一个位字段来检查是否有可选字段。

此外,如果建议的解决方案有效,如果这是针对多个项目(> 100000)的列表实施的,那么保存 memory 会更好吗?

这段代码可以按我的要求做吗?

好吧,它可以,但你不能依赖它。 不要这样做; 这不是编写正确程序的方法。

当你写b->x = 22; ,编译器有权表现得好像在b处有一个完整的struct test 您可能会想,“我只是将 22 放入成员x的字节中”,但编译器可能会使用“存储 8 个字节”指令:

  • 考虑一些架构,其中 memory 被组织成八字节组。 总线只能读取和写入整个 8 字节块。
  • 由于无法在硬件中写入四个字节,因此将四个字节写入 memory 需要读取八个字节,在处理器寄存器中操作它们以在其中四个字节中插入所需的值,然后将八个字节写回 memory。
  • 编译器要优化b->x = 22; ,并且它知道y尚未设置,因此允许它具有任何值。 因此,编译器不会使用低效的写入四字节序列,而是生成一个八字节存储,将 22 放入b->x并将 0 放入b->y

然后这会失败,因为编译器刚刚将 0 写入 memory 可能正在用于其他用途,因为它不是您为b分配的空间的一部分。

“如果你对编译器撒谎,它就会报仇雪恨。” — 亨利·斯宾塞

What you're attempting doesn't conform to the C standard because you're attempting to use an object of type struct test that doesn't have enough memory allocated for it, even though you're only accessing the fields for which memory was分配。 可能有效,但你不能依赖它。

可以做的是使用灵活的数组成员

struct test {
  int x;
  int y[];
};

在这样的结构中, sizeof(struct test)不包括最后一个成员。 您可以通过为结构分配空间以及所需的最后一个成员的尽可能多的数组元素来使用这样的结构。 例如:

struct test *b = malloc(sizeof(*b) + sizeof(int));
b->x = 1;
b->y[0] = 2;

您需要使用数组索引来访问最后一个成员,但这是一种以符合标准的方式执行所需操作的方法。

然后,如果您不想要最后一个成员,请执行以下操作:

struct test *b = malloc(sizeof(*b));
b->x = 1;

我认为您提出的解决方案很危险。 使用两种不同的结构:

struct test_x {
   int x;
};

struct test_xy {
  int x;
  int y;
};

要么有两个 arrays 要么将 void * 与鉴别器(例如标记指针)一起存储到其中一个。 另一个选项是对可选元素使用指针,但 sizeof(int *) 至少在我的盒子上与 sizeof(int) 相同,这样只会使事情变大。

如果所有 y 成员都是可选的,请考虑列布局,或者您可以对数据进行排序,以便所有 xy 元素排在第一位:

struct test_column {
  int *x;
  int *y;
};

struct test_column t = {
  .x = malloc(100000 * sizeof(int)),
  .y = 0

它对您没有帮助,但联合是两个结构共享 memory 的标准方式,因此每个元素的大小是 max(sizeof(test_xy), sizeof(test_x)) 而不是 sizeof(test_xy) + sizeof(test_x)。

最后,考虑压缩,特别是如果您使用 test_column 格式。

我 state 我不是 C 方面的专家,但我正在研究它。
我正在实现一个结构,我需要(在运行时)有一个可选字段。
所以我想到了这个:

//...
#include <stdlib.h>

struct test {
  int x;  // Must be
  int y;  // Optional (Must be the last field..(?))
};

int main(int argc, char **argv) {
    // With the optional field
    struct test *a = malloc(sizeof(*a));
    a->x = 11;
    a->y = 55;
    
    // Without the optional field
    struct test *b = malloc(sizeof(*b) - sizeof(int));
    b->x = 22;
    
    // ...
    
    free(a);
    free(b);
    return 0;
}

这段代码可以按我的要求做吗?
可能添加一个位字段来检查是否有可选字段...


此外,如果建议的解决方案有效,如果这是针对多个项目(> 100000)的列表实施的,那么保存 memory 会更好吗?


谢谢大家,提前。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM