在C中释放向上转型的结构体,安全吗?

问题描述 投票:0回答:2

我正在编写一些多态 C 代码,我想知道下面介绍的两个内存释放函数是否都能正常工作。我很确定

void free_casted_parent(Parent* parent)
是正确的,但我开始想知道内部的专业化是否有必要?

typedef enum {
    CHILD_TYPE_1,
    CHILD_TYPE_2,
} Kind;

typedef struct {
    Kind kind;
} Parent;

typedef struct {
    Kind kind;
    int value;
} ChildType1;

typedef struct {
    Kind kind;
    float other_value;
} ChildType2;


void free_parent(Parent* parent) {
    free(parent);
}

void free_casted_parent(Parent* parent) {
    switch (parent->kind) {
        case CHILD_TYPE_1:
            free((ChildType1*) parent);
            break;
        case CHILD_TYPE_2:
            free((ChildType2*) parent);
            break;
    }
}

int main() { 
    ChildType1* ptr1 = malloc(sizeof(ChildType1));
    ChildType2* ptr2 = malloc(sizeof(ChildType2));

    // do some stuff with both variants of parent
    
    free_parent((Parent*) ptr1);
    free_casted_parent((Parent*) ptr2);

    return 0;
}

如果

free_casted_parent(Parent* parent)
不正确,这与释放堆分配的值数组有什么不同?在这两种情况下,我们都传递有效地址而不指定确切的大小

c memory polymorphism
2个回答
0
投票

是的,它可以正常工作,但过于复杂,相反:

free(ptr1);
free(ptr2);

任何对象指针都可以与

void *
进行转换,这就是
free()
的操作。

您缺少

#include <stdlib.h>

malloc()
返回 NULL(出错时),这将导致
parent->
出现段错误。您想检查一下。


0
投票

所示代码中的所有指针转换均由 C 2018 6.3.2.3 7 定义:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未针对引用类型正确对齐,则行为未定义。否则,当再次转换回来时,结果将与原始指针相等......

由于指针是用

malloc
分配的,它为任何基本类型提供了适合寻址的内存,因此上面的第二句话不适用,并且定义了行为。

唯一显示的引发未定义行为问题的代码是

switch (parent->kind)
。 (代码中可能存在
// do some stuff with both variants of parent
中未显示的问题。)这里使用类型
Parent
访问内存,但我们不知道内存的有效类型是什么,因为动态分配内存的有效类型取决于用于将值存储到内存的类型,并且未显示该代码。推测使用了
ChildType1
ChildType2
,在这种情况下,此访问可能违反 C 2018 6.5 7 中的别名规则,因此具有未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.