释放分配给 char*(由 malloc 分配)的 int* 是否会调用未定义的行为?

Does freeing an int* which was assigned to a char* (allocated by `malloc`) invoke Undefined Behavior?

标题可能令人困惑。假设strmalloc分配的指针。类型 int*ptr 被分配给它并被释放,如下面的代码片段所示:

char* str = malloc(64);
int* ptr = str;

free(ptr);

我试过编译上面的代码。它只是给出一个警告:

source_file.c: In function ‘main’:
source_file.c:10:16: warning: initialization from incompatible pointer type
     int* ptr = str;
                ^

上面的代码是否调用了未定义的行为?
上面的代码片段是否释放了 mallocstr 分配的内存?

Does the above code invoke Undefined Behavior?

视情况而定。

来自 C11 草案 6.3.2.3/7:

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned) for the referenced type, the behavior is undefined.

由于 char 的对齐方式可能与 int 的对齐方式不同,这可能限制较少,因此将 char * pc 分配给 int * pi 可能会导致 pi 未对齐。

然而,对于 OP 给出的 具体 示例:

char * pc = malloc(64);
int * pi = pc;

行为将被定义为(参见 Alter Mann's malloc() 保证 return 一块内存正确对齐。

来自 C11 草案 7.22.3:

The pointer returned [by aligned_alloc, calloc, malloc, and realloc] if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement ...

导致未定义行为的示例是:

char * pc = malloc(64);
int * pi = pc + 1;

Does the above code snippet free the memory allocated by malloc for str?

如果之前的赋值会引入未定义的行为,则此问题无关紧要,因为已经调用 UB 时可能会发生任何事情。

如果否则之前的赋值不会调用 UB,则对 free() 的调用将完全取消分配引用的内存块,因为将指针值从 int * 转换回 void *,最初由 malloc() 提供,定义明确。

来自 C11 草案 6.3.2.3/7(续/):

Otherwise, when converted back again, the result shall compare equal to the original pointer

来自 C11 草案 6.3.2.3/1:

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer

它可能会在访问时根据字节顺序、对齐方式或此类 int 与 char 类型转换调用 UB。当你执行 malloc 时,它所做的只是 return a void* ,它可以是任何数据类型(在某些情况下可能需要类型转换)。如果将 char* 中的指针指向 int* 并没有什么区别,但是访问单元会有所不同,即一次 4 个字节的 int 与一次 1 个字节的 char 的情况。因此,您问题中的代码不会调用 UB,但内存访问可能会调用。

至于第二个问题,是的,在 ptr 上调用 free 会导致 str 指向的内存也被释放。现在,str 将是一个悬挂指针。

没有。它不会调用 未定义的行为。警告只是关于您可以强制转换的不兼容类型。

char* str = malloc(64);
int* ptr = (int*) str;
free(ptr);

free 确实采用了 void 指针,上面没有问题。但是,由于 int 类型和 char 类型的对齐,使用这样一个值的结果 可能 调用未定义的行为。因此 char*int* 本身的转换不会导致未定义。

Does the above code invoke Undefined Behavior?

没有

Does the above code snippet free the memory allocated by malloc for str?

是的。

为了澄清,关于 UB 的一些关于动态分配的注释:

malloc 返回的内存已对齐以获取任何可能的值。此类内存没有声明类型,其有效类型通过存储设置。

如果你这样做

*ptr = 42;

内存块的前 sizeof (int) 个字节现在是 int 类型并且只能这样读取,即

float val = *(float *)ptr;

将成为 UB。

然而,

*(float *)ptr = 42.0;

是合法的,因为它重新设置了有效类型,现在反过来使 *ptr 的读取无效。

此外,通过 charunsigned char 类型的指针访问任何对象始终是合法的。