将struct *强制转换为int *以便能够写入第一个字段

3
我最近发现了这个页面:使PyObject_HEAD符合标准C,我对其中的一段话很感兴趣:
“标准C有一个特定的例外,旨在支持Python的情况,即结构类型的值也可以通过指向第一个字段的指针访问。例如,如果一个结构以int开头,则struct *也可以转换为int *,从而允许将int值写入第一个字段。”
因此,我编写了这段代码来检查我的编译器:
struct with_int {
    int a;
    char b;
};

int main(void)
{
    struct with_int *i = malloc(sizeof(struct with_int));
    i->a = 5;
    ((int *)&i)->a = 8;
}

但我收到了错误信息:请求在非结构体或联合体中访问成员“a”。

上面的段落是否理解正确?如果不是,请指出我做错了什么? 另外,如果有人知道C标准是参考这个规则,请在此指出。谢谢。


1
应该将 ((int *)&i) 改为 ((int *)i) - Haris
或者它可以是 *(int *)&i - Archie Gertsman
啊,是的,“i”已经保存了一个地址。但我认为它需要被取消引用:*(int *)i, 对吗? - Archie Gertsman
@ArchieGertsman 这与之前的示例不同,但它可以工作。 - 2501
@Haris:不,它完全相同。 - kashpersky
显示剩余2条评论
3个回答

6

您的解释1是正确的,但代码不正确。

指针 i 已经指向对象,因此指向第一个元素,所以您只需要将其转换为正确的类型:

int* n = ( int* )i;

然后你只需取消引用它:
*n = 345;

或者一步到位:

*( int* )i = 345;

1 (摘自:ISO:IEC 9899:201X 6.7.2.1 结构体和联合体说明符15)
在结构体对象内,非位域成员和位域所在的单元具有按照它们被声明的顺序递增的地址。适当转换后,指向结构体对象的指针指向其初始成员(或如果该成员是位域,则指向其所在的单元),反之亦然。结构体对象内可能存在未命名的填充,但不会在其开头处出现。


谢谢,现在我明白了 :) - kashpersky

1
您有一些问题,但这对我来说可以工作:

#include <malloc.h>
#include <stdio.h>

struct with_int {
    int a;
    char b;
};

int main(void)
{
    struct with_int *i = (struct with_int *)malloc(sizeof(struct with_int));
    i->a = 5;
    *(int *)i = 8;
    printf("%d\n", i->a);
}

输出为:

8


0

就像其他答案所指出的那样,我认为你的意思是:

// Interpret (struct with_int *) as (int *), then
// dereference it to assign the value 8.
*((int *) i) = 8;

而不是:

((int *) &i)->a = 8;

然而,没有一个答案能够具体解释为什么这个错误是有意义的。

让我解释一下((int *) &i)->a的含义:

i是一个变量,它保存了一个指向(struct with_int)的地址。 &i是主函数堆栈空间上的地址。这意味着&i是一个包含指向(struct with_int)的地址的地址。换句话说,&i是指向指针(struct with_int)的指针。然后,对此进行的强制转换(int *)会告诉编译器将此堆栈地址解释为int指针,也就是int的地址。最后,使用->a,您要求编译器从这个int指针中获取结构成员a,然后将值8赋给它。从int指针中获取结构成员是没有意义的。因此,您会得到error: request for member 'a' in something not a struct or union

希望这可以帮助您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接