标题可能令人困惑。假设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
分配的内存?
答案 0 :(得分:11)
上面的代码是否会调用未定义的行为?
取决于。
从C11草案6.3.2.3/7开始:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果 对于引用的类型,结果指针未正确对齐),行为是 未定义。
由于char
的对齐方式可能与int
不同,因此可能限制性较小,将char * pc
分配给int * pi
可能会导致{{1}未对齐。
但是对于OP给出的特定示例:
pi
行为将被定义,因为(参见 Alter Mann ' s comment)char * 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
的读取无效。
此外,通过char
或unsigned char
类型的指针访问任何对象始终是合法的。
答案 3 :(得分:0)
它可以调用UB,基于字节顺序,对齐或访问时的类型与字符串类型转换。当你做malloc时,它所做的就是返回一个void*
,它可以是任何数据类型(在某些情况下可能需要进行类型转换)。如果你把一个指针放在char *到int *中,它就没有什么区别,但访问单元会有所不同,即一次只有4个字节,一次只有1个字节。因此,您的问题中的代码不会调用UB,但内存访问可能会。
关于第二个问题,是ptr
上的免费调用将导致str
指向的内存也被释放。现在,str
将是一个悬空指针。