Vla*_*nev 8 c polymorphism strict-aliasing language-lawyer type-punning
我一直试图弄清楚以下是合法的,我真的可以使用一些帮助.
#include <stdio.h>
#include <stdlib.h>
typedef struct foo {
int foo;
int bar;
} foo;
void make_foo(void * p)
{
foo * this = (foo *)p;
this->foo = 0;
this->bar = 1;
}
typedef struct more_foo {
int foo;
int bar;
int more;
} more_foo;
void make_more_foo(void * p)
{
make_foo(p);
more_foo * this = (more_foo *)p;
this->more = 2;
}
int main(void)
{
more_foo * mf = malloc(sizeof(more_foo));
make_more_foo(mf);
printf("%d %d %d\n", mf->foo, mf->bar, mf->more);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这样做就是打字,并且应该违反严格的别名规则.不过吗?传递的指针无效.您可以按照自己的意愿解释无效指针,对吗?
另外,我读到可能存在内存对齐问题.但结构对齐是确定性的.如果初始成员是相同的,那么它们将以相同的方式对齐,并且从more_foo指针访问所有foo成员应该没有问题.那是对的吗?
GCC在没有警告的情况下编译-Wall,程序按预期运行.但是,我不确定它是否是UB以及为什么.
我也看到了这个:
typedef union baz {
struct foo f;
struct more_foo mf;
} baz;
void some_func(void)
{
baz b;
more_foo * mf = &b.mf; // or more_foo * mf = (more_foo *)&b;
make_more_foo(mf);
printf("%d %d %d\n", mf->foo, mf->bar, mf->more);
}
Run Code Online (Sandbox Code Playgroud)
似乎是被允许的.由于联合的多态性,编译器可以使用它.那是对的吗?这是否意味着通过使用严格别名进行编译,您不必使用联合并且只能使用结构?
编辑:union baz
现在编译.
我想说这并不严格,因为如果你改变“foo”结构,“more foo”结构也必须随之改变。“foo”必须成为“more foo”的基础,这是继承,而不是多态。但是您可以使用函数指针引入多态性来帮助处理这些结构。
例子
#include <stdio.h>
#include <stdlib.h>
#define NEW(x) (x*)malloc(sizeof(x));
typedef struct
{
void(*printme)(void*);
int _foo;
int bar;
} foo;
typedef struct
{
// inherits foo
foo base;
int more;
} more_foo;
void foo_print(void *t)
{
foo *this = (foo*)t;
printf("[foo]\r\n\tfoo=%d\r\n\tbar=%d\r\n[/foo]\r\n", this->bar, this->_foo);
}
void more_foo_print(void *t)
{
more_foo *this = t;
printf("[more foo]\r\n");
foo_print(&this->base);
printf("\tmore=%d\r\n", this->more);
printf("[/more foo]\r\n");
}
void foo_construct( foo *this, int foo, int bar )
{
this->_foo = foo;
this->bar = bar;
this->printme = foo_print;
}
void more_foo_construct(more_foo *t, int _foo, int bar, int more)
{
foo_construct((foo*)t, _foo, bar);
t->more = more;
// Overrides printme
t->base.printme = more_foo_print;
}
more_foo *new_more_foo(int _foo, int bar, int more)
{
more_foo * new_mf = NEW(more_foo);
more_foo_construct(new_mf, _foo, bar, more);
return new_mf;
}
foo *new_foo(int _foo, int bar)
{
foo *new_f = NEW(foo);
foo_construct(new_f, _foo, bar);
return new_f;
}
int main(void)
{
foo * mf = (foo*)new_more_foo(1, 2, 3);
foo * f = new_foo(7,8);
mf->printme(mf);
f->printme(f);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
创建“more foo”时 printme() 被覆盖。(多态性)
more_foo 包括 foo 作为基本结构(继承),因此当“foo”结构更改时,“more foo”随之更改(例如添加的新值)。
more_foo 可以转换为“foo”。