问题描述
如果我有结构定义,例如,像这样:
If I have structure definitions, for example, like these:
struct Base {
int foo;
};
struct Derived {
int foo; // int foo is common for both definitions
char *bar;
};
我可以做这样的事情吗?
Can I do something like this?
void foobar(void *ptr) {
((struct Base *)ptr)->foo = 1;
}
struct Derived s;
foobar(&s);
换句话说,当它的类型实际上是 Derived *
时,我可以将 void 指针转换为 Base *
以访问它的 foo
成员吗?
In other words, can I cast the void pointer to Base *
to access its foo
member when its type is actually Derived *
?
推荐答案
许多现实世界的 C 程序假定您展示的构造是安全的,并且有对 C 标准的解释(特别是公共初始序列"规则,C99 §6.5.2.3 p5) 符合该规则.不幸的是,在我最初回答这个问题后的五年里,我可以轻松获得的所有编译器(即 GCC 和 Clang)都收敛于对共同初始序列规则的不同的、更窄的解释,在该规则下,您展示的构造引发未定义的行为.具体来说,试验这个程序:
Many real-world C programs assume the construct you show is safe, and there is an interpretation of the C standard (specifically, of the "common initial sequence" rule, C99 §6.5.2.3 p5) under which it is conforming. Unfortunately, in the five years since I originally answered this question, all the compilers I can easily get at (viz. GCC and Clang) have converged on a different, narrower interpretation of the common initial sequence rule, under which the construct you show provokes undefined behavior. Concretely, experiment with this program:
#include <stdio.h>
#include <string.h>
typedef struct A { int x; int y; } A;
typedef struct B { int x; int y; float z; } B;
typedef struct C { A a; float z; } C;
int testAB(A *a, B *b)
{
b->x = 1;
a->x = 2;
return b->x;
}
int testAC(A *a, C *c)
{
c->a.x = 1;
a->x = 2;
return c->a.x;
}
int main(void)
{
B bee;
C cee;
int r;
memset(&bee, 0, sizeof bee);
memset(&cee, 0, sizeof cee);
r = testAB((A *)&bee, &bee);
printf("testAB: r=%d bee.x=%d
", r, bee.x);
r = testAC(&cee.a, &cee);
printf("testAC: r=%d cee.x=%d
", r, cee.a.x);
return 0;
}
在启用优化(并且没有 -fno-strict-aliasing
)的情况下编译时,GCC 和 Clang 都将假定 testAB
的两个指针参数不能指向同一个对象,所以我得到像
When compiling with optimization enabled (and without -fno-strict-aliasing
), both GCC and Clang will assume that the two pointer arguments to testAB
cannot point to the same object, so I get output like
testAB: r=1 bee.x=2
testAC: r=2 cee.x=2
他们没有对 testAC
做出这样的假设,但是 - 之前的印象是 testAB
需要被编译,就好像它的两个参数可以 指向同一个对象——我对自己对标准的理解不再有足够的信心来判断 那个 是否可以保证继续工作.
They do not make that assumption for testAC
, but — having previously been under the impression that testAB
was required to be compiled as if its two arguments could point to the same object — I am no longer confident enough in my own understanding of the standard to say whether or not that is guaranteed to keep working.
这篇关于是否可以将指针从结构类型转换为另一种扩展 C 中第一个的结构类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!