我遇到了一段似乎同时使用不同成员联合的代码:
XEvent ev;
if(handler[ev.type])
(handler[ev.type])(&ev);
Handler是一组函数。这是XEvent的定义:
typedef union _XEvent{
int type;/*must not be changed*/
XAnyEvent xany;
XKeyEvent xkey;
XButtonEvent xbutton;
............
} Xevent;
XEvent的所有struct成员都有一个int作为第一个成员。被调用的函数使用XEvent的适当成员结构。
void
kpress(XEvent *ev) {
XKeyEvent *e = &ev->xkey;
问题是XKeyEvent
似乎也使用其第一个int成员的值来确定该事件是按键还是键释放。
typedef struct {
int type; /* KeyPress or KeyRelease */
unsigned long serial; /* # of last request processed by server */
.............
} XKeyEvent;
我在这里缺少什么?
注意:以上代码属于简单终端,终端仿真器。所有提到的数据结构都属于Xlib。
答案 0 :(得分:2)
我花了一段时间才知道你认为你的问题在哪里 - 因为实际上没有...
您似乎假设事件类型整数与结合中有效的结构之间必须存在1:1的关系。不,没有。
Xlib的作用是:它将为KeyPress和KeyRelease事件设置相同的XKeyEvent结构(它们使用相同的数据成员,因此可用于两种事件情况)。
X11窗口系统将XEvents作为不透明结构(或在OOP术语"基类")中发送,接收器可以转换为原始结构(或在OOP术语"派生类")根据事件类型。重叠的int
成员"类型"用作类型选择器。
这样做是为了能够"路由"通用代码中的事件到正确的位置而不必处理每个事件类型。只有感兴趣的一方(实际的接收方)才会将内部联盟转换为正确的类型,并且#34;提取"它感兴趣的数据成员。
答案 1 :(得分:1)
C99(以前的C标准)和现在的C11,即使不是最后一个成员,也允许阅读工会会员。
他们声明(并且我会解释)最后写成员的价值被重新解释为正在阅读的成员的价值(如果他们的规模不同,则表现为"人们会期望&# 34)。该值可能是陷阱值,但允许简单的读取操作,而不是未定义的行为。
现在,该标准还指定如果联合包含多个共享相同初始序列的成员结构,则可以通过任何联合成员检查公共序列。
type
中的{p> XEvent
不是一个结构,但标准中又说了两件事:
因此,每个结构中的每个type
必须与type
中的XEvent
位于同一内存位置。因此,无论您正在阅读ev.type
还是ev.xkey.type
,它都将是相同的int。
所以你的代码中发生了什么:
联合用于类型擦除。只有type
字段用于确定正确的处理程序。没有任何事情可以阻止在handler
中在type
的几个值上注册相同的功能。
处理程序知道要查看的联合成员,因此它访问xkey
。然后它根据type
。