问题 是否可以使用指向第一个成员的指针自由调用?


是否可以在指向结构的第一个成员的指针上调用free(并且结构是与malloc相关的结构)?我原则上知道指针指向正确的东西......

struct s {int x;};
//in main
struct s* test;
test = (struct s*) malloc(sizeof(*test));
int* test2;
test2 = &(test->x);
free(test2); //is this okay??

此外,如果答案会改变 int x 被结构替换?

更新:为什么我要编写这样的代码?

struct s {int x;};
struct sx1 {struct s test; int y;}; //extending struct s
struct sx2 {struct s test; int z;}; //another
// ** some functions to keep track of the number of references to each variable of type struct s 
int release(struct s* ptr){
  //if the number of references to *ptr is 0 call free on ptr
}
int main(){
    struct sx1* test1;
    struct sx2* test2;
    test1 = (sx1*) malloc(sizeof(*sx1));
    test2 = (sx2*) malloc(sizeof(*sx2));
    //code that changes the number of references to test1 and test2, calling functions defined in **
    release(test1);
    release(test2);
}

4317
2018-04-13 12:45


起源

是的这是对的。 - Akash Chandwani
@ user71815我认为没必要,更好的编译和检查。 (然后告诉我们) - Akash Chandwani
你为什么要写这样的代码? - Lundin
这绝对是一件奇怪的事情。我永远不会写这样的代码。为什么不释放原始指针,而不是试图从结构成员的地址推断它? - Tom Karzes
@TomKarzes是的 - 当有人在开始时推动另一件事情时会发生什么? - Martin James


答案:


是的,这没关系。

6.7.2.1

  1. 在结构对象内,非位字段成员和位域中的单位   驻留的地址按声明的顺序增加。 指向a的指针   结构对象,适当转换,指向其初始成员(或者如果该成员是a   比特字段,然后到它所在的单元,反之亦然。 可能有未命名的   在结构对象中填充,但不在其开头。

这意味着这是定义的:

struct s {int x;};
struct s* test;
test = (struct s*) malloc(sizeof(*test));
int* p = &(test->x);
free(p);

7
2018-04-13 12:50



是的,从某种意义上说,行为是由标准定义的,并且可能是预期的。但不,确实如此 不 好的,因为它是糟糕的风格,因为如果修改了结构定义,它会在以后出现令人惊讶的失败的途径。 - John Bollinger
该标准不保证指向一种类型的指针与指向另一种类型的指针相同,除了 char *。因此,不,它是 不好。它恰好在(最重要的)所有最近的实现上工作,因为它们使用统一的地址空间。 - too honest for this site
即使这两个指针, s 和 p,具有不同的大小,不同的对齐方式,并且具有不同的表示,它们仍然指向相同的地址和相同的对象,因此使用任一来释放内存都是严格遵守的。 - 2501
他们肯定不指向同一个对象。原因应该清楚:类型不同。我跟你说说地址。 7.22.3.3p2也是相关的。考虑到/来自的转换 void * 不过,你似乎是对的。我仍然认为这是不好的做法,可能会混淆静态代码检查器。无论如何,我撤回了我的反对意见,但你的回答应该有更多的信息。 - too honest for this site
@Olaf:获取结构第一项的地址相当于将该结构的地址转换为该类型。该操作可能在某些实现中涉及更改指针的位表示,但如果从malloc返回的非null void *开始,则将指针转换为任何指针到数据类型的序列并返回到void *是保证产生原始指针。 - supercat


根据C11标准,章节§6.7.2.1

[...]可能有未命名的   在结构对象中填充,但不在其开头。

这意味着在结构的开头不能有任何填充。因此,第一个成员将具有与结构变量相同的地址。

free() 需要一个先前已经返回的指针 malloc() 或家人。

在您的情况下,您传递的是相同的地址 malloc() 回来了。所以,你很高兴。


5
2018-04-13 12:49