单个malloc中的多个结构调用未定义的行为? [英] Multiple structures in a single malloc invoking undefined behaviour?

查看:63
本文介绍了单个malloc中的多个结构调用未定义的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自在声明灵活数组成员时使用正确的语法,它表示当 malloc 用于标头和灵活数据时, data [1]] 被入侵到 struct

From Use the correct syntax when declaring a flexible array member it says that when malloc is used for a header and flexible data when data[1] is hacked into the struct,

当访问其他任何元素时,此示例具有未定义的行为比数据数组的第一个元素.(请参阅C标准,6.5.6.)因此,编译器可以生成不返回代码的代码.访问数据的第二个元素时的期望值.

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 Standard 6.5.6,但看不到它将如何产生不确定的行为.我使用了一种我喜欢的模式,其中使用相同的 malloc

I looked up the C Standard 6.5.6, and could not see how this would produce undefined behaviour. I've used a pattern that I'm comfortable with, where the header is implicitly followed by data, using the same sort of 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 灵活的数组成员.该页面还显示,

The compliant solution uses C99 flexible array members. The page also says,

在声明灵活数组时未能使用正确的语法成员可能会导致未定义的行为,尽管语法不正确将可用于大多数实现.

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是不正确的?)对它不起作用的实现因素是什么?

Technically, does this C90 code produce undefined behaviour, too? And if not, what is the difference? (Or the Carnegie Mellon Wiki is incorrect?) What is the factor on the implementations this will not work on?

推荐答案

应明确定义:

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

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

Because you create a pointer to one element past the end of an array of size 1 but do not dereference it. And because a->array now points to bytes that do not yet have an effective type, you can use them safely.

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

This only works however because you're using the bytes that follow as an array of char. If you instead tried to create an array of some other type whose size is greater than 1, you could have alignment issues.

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

For example, if you compiled a program for ARM with 32 bit pointers and you had this:

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

您的程序可能由于未对齐写入而崩溃.因此,一般而言,您不应该依赖于此.最好坚持使用标准保证可以使用的灵活数组成员.

Your program would crash due to a misaligned write. So in general you shouldn't depend on this. Best to stick with a flexible array member which the standard guarantees will work.

这篇关于单个malloc中的多个结构调用未定义的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆