释放分配给char *的int *(由`malloc`分配)是否会调用Undefined Behavior?

时间:2015-05-02 08:44:08

标签: c pointers memory free undefined-behavior

标题可能令人困惑。假设str是由malloc分配的指针。类型为ptr的{​​{1}}被分配给它并被释放,如下面的代码段所示:

int*

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

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分配的内存?

4 个答案:

答案 0 :(得分:11)

  

上面的代码是否会调用未定义的行为?

取决于。

从C11草案6.3.2.3/7开始:

  

指向对象类型的指针可以转换为指向不同对象类型的指针。如果   对于引用的类型,结果指针未正确对齐),行为是   未定义。

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

但是对于OP给出的特定示例:

pi

行为将被定义,因为(参见 Alter Mann ' s commentchar * pc = malloc(64); int * pi = pc; 保证返回正确对齐的内存块

从C11草案7.22.3开始:

  

在   指针返回[通过aligned_alloc,calloc,malloc和realloc],如果分配成功,则适当对齐,以便可以将其分配给   指向具有基本对齐要求的任何类型对象的指针...

由于未对齐,导致未定义行为的示例是:

malloc()
  

上面的代码片段是否释放了malloc为str?

分配的内存

如果前一个赋值会引入未定义的行为,那么这个问题就无关紧要了,因为UB已经被调用了。

如果先前的赋值不会调用UB,则对char * pc = malloc(64); int * pi = pc + 1; 的调用将完全取消分配引用的内存块,因为将指针值从free()转换回{最初由int *提供的{1}}定义明确。

从C11草案6.3.2.3/7(续):

  

否则,当再次转换回来时,结果应该等于   原始指针

从C11草案6.3.2.3/1:

  

指向void的指针可以转换为指向任何对象类型的指针。指向的指针   任何对象类型都可以转换为指向void的指针,然后再返回;结果应该   比较等于原始指针

答案 1 :(得分:4)

没有。它没有调用未定义的行为。警告只是关于你可以施放的不兼容类型。

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

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

答案 2 :(得分:1)

  

上面的代码是否会调用未定义的行为?

没有

  

上面的代码片段是否释放了malloc为str?

分配的内存

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

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

如果你这样做

*ptr = 42;

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

float val = *(float *)ptr;

将是UB。

然而,

*(float *)ptr = 42.0;

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

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

答案 3 :(得分:0)

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

关于第二个问题,是ptr上的免费调用将导致str指向的内存也被释放。现在,str将是一个悬空指针。