gpt4 book ai didi

c - 单个 malloc 中的多个结构调用未定义的行为?

转载 作者:太空狗 更新时间:2023-10-29 16:10:02 25 4
gpt4 key购买 nike

来自 Use the correct syntax when declaring a flexible array member它说当 data[1] 被黑入 struct 时,当 malloc 用于 header 和灵活数据时,

This example has undefined behavior when accessing any element other than the first element of the data array. (See the C Standard, 6.5.6.) Consequently, the compiler can generate code that does not return the expected value when accessing the second element of data.

我查阅了 C 标准 6.5.6,但看不出这会如何产生未定义的行为。我使用了一种我喜欢的模式,其中 header 隐式地跟在数据之后,使用相同类型的 malloc

#include <stdlib.h> /* EXIT malloc free */
#include <stdio.h> /* printf */
#include <string.h> /* strlen memcpy */

struct Array {
size_t length;
char *array;
}; /* +(length + 1) char */

static struct Array *Array(const char *const str) {
struct Array *a;
size_t length;
length = strlen(str);
if(!(a = malloc(sizeof *a + length + 1))) return 0;
a->length = length;
a->array = (char *)(a + 1); /* UB? */
memcpy(a->array, str, length + 1);
return a;
}

/* Take a char off the end just so that it's useful. */
static void Array_to_string(const struct Array *const a, char (*const s)[12]) {
const int n = a->length ? a->length > 9 ? 9 : (int)a->length - 1 : 0;
sprintf(*s, "<%.*s>", n, a->array);
}

int main(void) {
struct Array *a = 0, *b = 0;
int is_done = 0;
do { /* Try. */
char s[12], t[12];
if(!(a = Array("Foo!")) || !(b = Array("To be or not to be."))) break;
Array_to_string(a, &s);
Array_to_string(b, &t);
printf("%s %s\n", s, t);
is_done = 1;
} while(0); if(!is_done) {
perror(":(");
} {
free(a);
free(b);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}

打印,

<Foo> <To be or >

兼容的解决方案使用 C99 灵活的数组成员。该页面还说,

Failing to use the correct syntax when declaring a flexible array member can result in undefined behavior, although the incorrect syntax will work on most implementations.

从技术上讲,这段 C90 代码是否也会产生未定义的行为?如果不是,有什么区别? (或者 Carnegie Mellon Wiki 不正确?)这将无法实现的实现的因素是什么?

最佳答案

这应该被很好地定义:

a->array = (char *)(a + 1);

因为您创建了一个指向大小为 1 的数组末尾后一个元素的指针,但没有取消引用它。因为 a->array 现在指向还没有有效类型的字节,所以您可以安全地使用它们。

但这仅适用于您将后面的字节用作 char 数组。如果您改为尝试创建大小大于 1 的其他类型的数组,则可能会出现对齐问题。

例如,如果您使用 32 位指针为 ARM 编译了一个程序,并且您有:

struct Array {
int size;
uint64_t *a;
};
...
Array a = malloc(sizeof *a + (length * sizeof(uint64_t)));
a->length = length;
a->a= (uint64_t *)(a + 1); // misaligned pointer
a->a[0] = 0x1111222233334444ULL; // misaligned write

您的程序会由于未对齐的写入而崩溃。所以一般来说你不应该依赖这个。最好坚持使用标准保证会起作用的灵活数组成员。

关于c - 单个 malloc 中的多个结构调用未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55014685/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com