释放分配给char *(由`malloc`分配)的int *是否会调用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分配的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读取无效。

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

它可以在访问时根据字节顺序,对齐或类似的int与char类型转换来调用UB。 当你做malloc时,它所做的就是返回一个void* ,它可以是任何数据类型(在某些情况下可能需要进行类型转换)。 如果你把一个指针放在char *到int *中没有区别,但是访问单元会有所不同,例如,一次只有4个字节,一次只有1个字节。 因此,您的问题中的代码不会调用UB,但内存访问可能会。

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