释放分配给 char*(由 malloc 分配)的 int* 是否会调用未定义的行为?
Does freeing an int* which was assigned to a char* (allocated by `malloc`) invoke Undefined Behavior?
标题可能令人困惑。假设str
是malloc
分配的指针。类型 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;
^
上面的代码是否调用了未定义的行为?
上面的代码片段是否释放了 malloc
为 str
分配的内存?
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
的读取无效。
此外,通过 char
或 unsigned char
类型的指针访问任何对象始终是合法的。
标题可能令人困惑。假设str
是malloc
分配的指针。类型 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;
^
上面的代码是否调用了未定义的行为?
上面的代码片段是否释放了 malloc
为 str
分配的内存?
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
的读取无效。
此外,通过 char
或 unsigned char
类型的指针访问任何对象始终是合法的。