为什么这个联盟显然持有不止一种价值观
Why is this union apparently holding more than one value?
我是使用并集的新手,对如何通过这个测试感到困惑,SDL_Event
是一个并集:
TEST(basic_check, test_eq) {
Dot dot;
SDL_Event event; // this is a union, see below
event.type = SDL_KEYDOWN; // <= I use one member here
SDL_Keysym keysym; // this is a struct
keysym.sym = SDLK_UP;
event.key.keysym = keysym; // <= I use another member here
dot.handleEvent(event); // <= but this function accesses value of the first member
EXPECT_EQ(-Dot::DOT_VEL, dot.getVelY());
}
我的理解是,一个工会只能拥有一种价值观。
然而,在这个测试中,我在联合的一个成员event.type
中设置了一个值;然后我更新了联盟的另一个成员event.key
。更确切地说,event.key
是一个结构,我更新它的成员,使其具有结构SDL_Keysym
。
这里是函数的代码,然后被调用:
void Dot::handleEvent(SDL_Event& e) {
if (e.type == SDL_KEYDOWN && e.key.repeat == 0) { //<== access two alternate members?
switch (e.key.keysym.sym) {
case SDLK_UP:
velY -= DOT_VEL;
break;
case SDLK_DOWN:
... // followed by a lot of other cases
}
}
}
我很困惑,因为if
条件访问联合的两个成员(请参阅上面的注释(。我以为它们会是独家的。
作为参考,SDL_Event
和SDL_KeyboardEvent
的定义如下:
typedef union SDL_Event
{
Uint32 type; /**< Event type, shared with all events */
SDL_CommonEvent common; /**< Common event data */
SDL_WindowEvent window; /**< Window event data */
SDL_KeyboardEvent key; /**< Keyboard event data */
... // and a long list of other events
...
} SDL_Event;
typedef struct SDL_KeyboardEvent
{
Uint32 type; /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
Uint32 timestamp;
Uint32 windowID; /**< The window with keyboard focus, if any */
Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */
Uint8 repeat; /**< Non-zero if this is a key repeat */
Uint8 padding2;
Uint8 padding3;
SDL_Keysym keysym; /**< The key that was pressed or released */
} SDL_KeyboardEvent;
工会在任何给定时间最多有一名成员是对的。
但该标准提供了一个保证,以便于使用并集(尤其是找出,如这里所示,哪一个是活动元素(:
9.5/1:(…(如果一个标准布局联合包含多个标准布局结构共享一个共同的初始序列,并且如果标准布局联合类型包含一个标准布局structs,允许检查任何标准布局结构成员的;
在您的示例中,SDL_Event
并集有一个并集成员Uint32 type
,所有SDL_XXXEvent
结构也都以Uint32
开头。这是常见的初始序列,因此可以使用任何成员对其进行检查(最简单的是type
(。
编辑:有趣的备注(取自备注(
正如您所指出的,测试不仅仅是检查:它还使用event.type
写入type
,然后在event.key
中分配keysym
。因此,您想知道活动成员(从type
到key
(的更改是否不会使公共初始序列无效。
请放心,这是完美的。检查的C++保证确保分配event.type
(公共初始序列(后,event.key.type
也是SDL_KEYDOWN
。由于您只更改event.key.keysim
,因此type
的值没有更改的原因。
然而,注意timestamp
、WindowsID
和event.key
的其他成员处于未定义状态。你的测试没有使用它们,所以没有理由失败。但为了避免这种潜在的问题,更好的方法是构造一个SDL_KeyboardEvent
,正确初始化它,并将整个结构复制到event.key
如果你仔细观察SDL_Event
,你会发现它主要是一个结构的unio,其中每个结构都有相同的初始签名(第一个成员是一个8位无符号整数(。
这就是它工作的原因。即使并集中的结构具有不同的大小,所有结构都将具有与第一个成员相同的成员type
。
这是一种模拟继承的简单方法,这意味着SDL_Event
并集中的所有结构都是彼此的兄弟。
此外,C规范明确允许使用并集将多个类型表示为一种类型punning。
然而 由于问题被标记为C++问题,从技术上讲,这是未定义的行为。
为了与C向后兼容,大多数(如果不是全部的话(C++编译器都允许这样做,而不会有任何抱怨。
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 有没有一种方法可以在编译时获得作用域类名
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 在 c++ 中,有一种方法可以创建一个包含地图作为值的树状地图?
- 有没有一种优雅而快速的方法来测试整数中的 1 位是否位于连续区域
- 在运行时检查继承是否只有一种类型和 void*
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 找到一种有效的方法,在 2 个巨大的缓冲区上执行 MAX,每字节字节
- 寻找一种更好的方法来表示无符号字符数组
- 为什么这个联盟显然持有不止一种价值观