【发布时间】:2019-02-07 09:33:41
【问题描述】:
我正在设计一个应用程序,但遇到了一个实施问题。我有以下结构定义:
app.h:
struct application_t{
void (*run_application)(struct application_t*);
void (*stop_application)(struct application_t*);
}
struct application_t* create();
当我试图“实现”这个application_t 时,问题就来了。我倾向于定义另一个结构:
app.c:
struct tcp_application_impl_t{
void (*run_application)(struct application_t*);
void (*stop_application)(struct application_t*);
int client_fd;
int socket_fd;
}
struct application_t* create(){
struct tcp_application_impl_t * app_ptr = malloc(sizeof(struct tcp_application_impl_t));
//do init
return (struct application_t*) app_ptr;
}
所以如果我按如下方式使用:
#include "app.h"
int main(){
struct application_t *app_ptr = create();
(app_ptr -> run_application)(app_ptr); //Is this behavior well-defined?
(app_ptr -> stop_application)(app_ptr); //Is this behavior well-defined?
}
让我感到困惑的问题是,如果我打电话给(app_ptr -> run_application)(app_ptr); yields UB。
app_ptr 的“静态类型”如果struct application_t*,但“动态类型”是struct tcp_application_impl_t*。 struct application_t 和 struct tcp_application_t 与 N1570 6.2.7(p1) 不兼容:
他们的成员之间应该有一对一的通信,例如 每对对应的成员都声明为 compatible 类型
在这种情况下显然不是真的。
您能否提供解释该行为的标准参考?
【问题讨论】:
-
看起来像“C 中的继承”黑客......也许将结构的第一个字段定义为
application_t类型会更好 -
你必须使用
struct tcp_application_impl_t { application_t base; int client_fd, socket_fd; },如果是cp_application_impl_t *p,那么在二进制级别上使用&p->base == p -
@Jean-FrançoisFabre 差不多,是的。我实际上不确定这是否是一种“常见的 C 方式”来做这样的事情......
-
我认为你需要
&app_ptr->base;increate()并使用void run_application(application_t* p) { tcp_application_impl_t*q = CONTAINING_RECORD(p, tcp_application_impl_t, base); ...}where#define CONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) -
行为,正如您正确指出的那样,是未定义的。该标准没有解释未定义的行为。
标签: c struct language-lawyer undefined-behavior