我正在设计一个应用程序并遇到一个实施问题。我有以下结构定义:
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);
收益率UP。
app_ptr 的“静态类型”如果struct application_t*
,但“动态类型”是struct tcp_application_impl_t*
. The struct application_t
and struct tcp_application_t
与 N1570 6.2.7(p1) 不兼容:
其成员之间应有一对一的对应关系,例如
每对对应的成员都声明为兼容的
类型
在本例中这显然是不正确的。
您能否提供解释该行为的标准参考?
您的两个结构不兼容,因为它们是不同的类型。您已经找到了“兼容类型”一章,它定义了使两个结构兼容的原因。当您使用指向错误类型的指针访问这些结构时,UB 会稍后出现,按照 6.5/7 严格别名违规。
解决这个问题的明显方法是这样的:
struct tcp_application_impl_t{
struct application_t app;
int client_fd;
int socket_fd;
}
现在类型可以别名,因为tcp_application_impl_t
是一个包含application_t
其成员中。
明确定义的另一种方法是使用隐藏在 C17 6.5.2.3/6 中的“联合公共初始序列”的特殊规则:
为了简化联合的使用,做出了一项特殊保证:如果联合包含
共享共同初始序列的几个结构(见下文),并且如果并集
对象当前包含这些结构之一,允许检查公共结构
其中任何一个的初始部分,声明联合的完整类型
是可见的。两个结构共享一个共同初始序列如果对应的成员
对于一个或多个初始成员的序列具有兼容的类型(对于位字段,具有相同的宽度)。
这将允许您使用声明的原始类型。但在同一个翻译单元中的某个地方,您必须添加一个虚拟联合 typedef 才能利用上述规则:
typedef union
{
struct application_t app;
struct tcp_application_impl_t impl;
} initial_sequence_t;
您不需要实际使用该联合的任何实例,它只需要保持可见即可。这告诉编译器这两种类型允许使用别名,只要它们的共同初始序列有效。在你的情况下,它意味着函数指针,而不是尾随变量tcp_application_impl_t
.
Edit:
免责声明。常见的初始序列技巧显然有点争议,编译器用它做的事情超出了委员会的预期。并且在 C 和 C++ 中的工作方式可能有所不同。看union '双关语'结构带有“公共初始序列”:为什么 C (99+) 而不是 C++ 规定了“联合类型的可见声明”? https://stackoverflow.com/questions/34616086/union-punning-structs-w-common-initial-sequence-why-does-c-99-but-not
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)