释放分配给char *(由`malloc`分配)的int *是否会调用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
分配的malloc
?
上面的代码是否调用未定义的行为?
这取决于。
从C11草案6.3.2.3/7开始:
指向对象类型的指针可以转换为指向不同对象类型的指针。 如果引用类型的结果指针未正确对齐),则行为未定义。
由于char
的对齐可能与int
不同,因此可能限制性较小,将char * pc
分配给int * pi
可能会导致pi
未对齐。
但是对于OP给出的具体例子:
char * pc = malloc(64); int * pi = pc;
行为将被定义,因为(参见Alter Mann的评论 ) malloc()
保证返回正确对齐的内存块。
从C11草案7.22.3开始:
如果分配成功,则[align_alloc,calloc,malloc和realloc]返回的指针被适当地对齐,以便可以将其分配给指向具有基本对齐要求的任何类型对象的指针……
由于未对准而导致未定义行为的示例是:
char * pc = malloc(64); int * pi = pc + 1;
上面的代码片段是否释放了malloc为str分配的内存?
如果前一个赋值会引入未定义的行为,那么这个问题就无关紧要了,因为UB已经被调用了。
如果否则先前赋值不会调用UB,则调用free()
将完全取消分配引用的内存块,如将指针值从int *
转换回void *
,最初由malloc()
,很明确。
从C11草案6.3.2.3/7(续):
否则,当再次转换回来时,结果应该等于原始指针
和
从C11草案6.3.2.3/1:
指向void的指针可以转换为指向任何对象类型的指针。 指向任何对象类型的指针可以转换为指向void的指针,然后再返回; 结果应该等于原始指针
不。它不会调用未定义的行为 。 警告只是关于您可以投射的不兼容类型。
char* str = malloc(64); int* ptr = (int*) str; free(ptr);
free
取一个void指针,上面没有问题。 但是,由于int类型和char类型的对齐,使用此类值的结果可能会调用未定义的行为。 因此,将char*
转换为int*
本身不会导致未定义。
上面的代码是否调用未定义的行为?
没有。
上面的代码片段是否释放了malloc为str分配的内存?
是。
仅仅是为了澄清,关于动态分配的UB的一些注释:
malloc
返回的malloc
对齐以获取任何可能的值。 此类内存没有声明类型,其有效类型通过存储设置。
如果你这样做
*ptr = 42;
内存块的第一个sizeof (int)
字节现在将是int
类型,并且只能这样读取,即
float val = *(float *)ptr;
将是UB。
然而,
*(float *)ptr = 42.0;
这将是合法的,因为它重新设置有效类型,现在反过来通过*ptr
读取无效。
此外,通过char
或unsigned char
类型的指针访问任何对象始终是合法的。
它可以在访问时根据字节顺序,对齐或类似的int与char类型转换来调用UB。 当你做malloc时,它所做的就是返回一个void*
,它可以是任何数据类型(在某些情况下可能需要进行类型转换)。 如果你把一个指针放在char *到int *中没有区别,但是访问单元会有所不同,例如,一次只有4个字节,一次只有1个字节。 因此,您的问题中的代码不会调用UB,但内存访问可能会。
至于第二个问题,是在ptr
上调用free会导致str
指向的内存也被释放。 现在, str
将是一个悬垂的指针。