3
4

2 回答 2

5

从技术上讲,该标准允许不同的对象指针类型具有不同的表示形式(甚至不同的大小),尽管char*并且void*要求具有相同的表示形式。但下面是UB:

int *ip = 0;
free(*(void**)(&ip));

仅仅是因为内存的ip大小不必与内存的大小相同void*,即使它是类型空指针的位模式也int*不必与类型空指针的位模式相同void*。如果它们不同,那么编译器当然必须插入代码以在您转换int*void*或转换回时在它们之间进行转换。

在实践中,实现不会对您这样做(例如 Posix 禁止这样做)。

更重要的是,严格的别名规则不允许您char*使用类型的左值访问对象void*。所以在实践中,对指针表示的担忧不会破坏你的代码,但优化器实际上可能会。基本上,如果函数调用myfree((void**)(&p))被内联,那么编译器可能会看到:

char *p = <something>;
void **data = (void**)(&p);
free(*data);
*data = NULL;
// code that reads p

优化器可以注意到它*data = NULL正在设置一个 type 的对象void*,而“读取 p 的代码”正在读取一个 type 的对象char*,它被禁止与那里的另一个void*对象别名。因此,允许重新排序指令,*data = NULL;完全消除,或者可能其他我没有想到的事情会毁了你的一天,但如果你没有违反规则,那会加速代码。

于 2012-06-08T18:07:21.457 回答
-1

您可以使用 MACRO 来执行此操作。与拥有功能相比,这将非常棒;我希望你知道使用 MACRO 的好处。

#define FREE_IF_NOT_NULL(x) if (x != NULL) { \
                                            free(x); \
                                            x = NULL; \
                                       }
于 2012-06-08T18:08:48.070 回答