【问题标题】:Two types in the same dynamic allocation同一动态分配中的两种类型
【发布时间】:2019-11-25 21:10:52
【问题描述】:

ISO C90 标准(或至少我所拥有的草案)说明了 malloc 和对齐方式:

如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问分配的空间中的此类对象或此类对象的数组...

但是你可以将malloc 返回的同一个指针用于两种不同的类型吗?例如,假设我知道sizeof(int) <= 2 * sizeof(short)。我能否为5shorts 分配足够的内存,并将前两个用作int,即以下代码是否保证按预期工作?

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    void* data = malloc(5 * sizeof(short));
    short* short_array = data;
    int* int_ptr = data;
    if (!data) return EXIT_FAILURE;
    *int_ptr = 13943;
    short_array += 2; /* Skip over the int */
    short_array[0] = 7;
    short_array[1] = 238;
    short_array[2] = -123;
    printf("%d %d %d %d\n", *int_ptr, short_array[0], short_array[1], short_array[2]);
    free(data);
    return 0;
}

我试过这段代码,它确实为我输出了13943 7 238 -123,但我不完全确定它是否符合标准。


编辑:具体来说,我正在尝试创建一个动态数组类型(可以是任何类型的数组),所以我正在分配一个类型的数组,并使用该分配的开始作为指向包含数组长度和容量的标头。

要清楚,这大概是我正在做的事情:

size_t header_elements = (sizeof(ArrayHeader) + array_type_size - 1) / array_type_size); /* = ceil(sizeof(ArrayHeader) / array_type_size) */
void* data = malloc((header_elements + array_length) * array_type_size);
ArrayHeader* header = data;
void* array = (char*)data + header_elements * array_type_size;

所以,header 指向分配的开始,实际的array 偏移了其中存储的类型大小的倍数。

【问题讨论】:

  • 我相信是的
  • @chux:为什么要删除你的答案?
  • DR28 中的重点是编译器可以优化,但在C90 文本中没有明确提及,因此您无法在其中找到任何相关引用。关键是它们指向同一个位置,在 C99 中被称为有效类型的东西。
  • 糟糕,我看错了。但无论如何,这就是说即使两个指针重叠,编译器也可以优化它,这在我的情况下是不正确的。
  • 将该分配的开始用作指向包含数组长度和容量的标头的指针 这意味着数组的其余部分不再“适当对齐,因此可以将它分配给指向任何类型对象的指针,然后用于访问分配的空间中的此类对象或此类对象的数组”,除非您已注意确保标头的大小与所需的对齐方式相匹配。对于 C11 及更高版本,您可以使用 _Alignof (max_align_t) 来确定。

标签: c malloc memory-alignment c89


【解决方案1】:

C90现在应该已经死了,安息吧。 C99、C11 和 C18 行为是此处应考虑的行为。他们谈论了很多有效的类型。由于malloc分配的对象不是这样类型的,编译器将跟踪每个指针和内存区域的类型。

如果您将int 写入前4 个字节,则允许编译器将前4 个字节的数据类型视为int。如果然后您将短写写入连续字节,它们的有效类型将是short如果存储没有重叠,那么你的代码就OK了。

但是 - 请注意:如果您重叠存储,即您将在int 上写入short,然后再读回int,那么所有的赌注都没有了.

最后有一个很好的避免歧义的方法——使用struct 类型。怎么办呢

struct two_types_in_one_malloc {
    int the_int;
    short the_shorts[3];
};

【讨论】:

  • 我要做的特别的事情是创建一个动态数组类型(所以我为数组分配空间,并使用第一部分作为长度和容量的标题),但是我希望它适用于所有类型,这就是为什么我不能“只”使用结构。至于“这里应该考虑 C99、C11 和 C18 的行为”,我问的是 C90,但是哦,好吧......
  • 那么请编辑您的问题,这样说!良好的动力
猜你喜欢
  • 2020-02-23
  • 2021-08-13
  • 2015-06-22
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
相关资源
最近更新 更多