C语言 在Windows中从函数返回一个结构体会破坏它的数据



我使用以下C结构体来报告2D游戏中的跟踪结果。

typedef struct TraceResult
{
bool collided;
bool beganColliding;
bool endedColliding;    // If the trace ended while still inside a collider
float fraction;
Vector2 endPosition;
Vector2 contactNormal;
struct Entity* collisionEnt;
ComponentType collisionComponentType;
} TraceResult;

结构被初始化如下:

TraceResult workingResult = TraceRectangleMovementAgainstTerrain(
hull,
delta,
Entity_GetTerrainComponent(ent),
collisionMask
);

调用完成后,将结构体传回给前一个函数的调用者。我在return语句前面放了一个printf,它报告了接触正常值是预期的:

printf("Contact normal before returning: (%.2f, %.2f)n", workingResult.contactNormal.x, workingResult.contactNormal.y);
return workingResult;
Contact normal before returning: (0.00, -1.00)

然而,在返回结构体的函数调用之后,我有另一个printf语句。这报告了接触法向是不同的-它似乎已经采取了endPosition成员之前的值:

printf("Contact normal after returning: (%.2f, %.2f)n", result.contactNormal.x, result.contactNormal.y);
Contact normal after returning: (995.00, 150.00)

当我在Ubuntu上运行应用程序时,这个问题不会发生,只有在Windows上才会发生。有时通过复制返回TraceResult是可以的,但其他时候这些值似乎会像这样损坏。是我疯了,还是编译器不配合?

我最终解决了这个问题:问题是我忽略了在定义结构体的头文件中添加#include <stdbool.h>。一旦我添加了这个,一切都开始像预期的那样工作。

我最初感到困惑,为什么这是这种情况-当然,如果没有bool的定义,编译器应该抛出一个错误?然而,经过一番搜索,我在我的第三方库头之一中找到了这个:

#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#elif !defined(__cplusplus) && !defined(bool)
typedef enum bool { false, true } bool;
#define RL_BOOL_TYPE
#endif

根据快速谷歌,MSVC只有在使用/Za编译选项时才定义__STDC__。因为我没有打开这个开关,所以库头使用了自己的bool类型,因为这是一个enum,所以它是4字节而不是1字节。这引起了关于结构体成员偏移量的混淆,这取决于编译单元在遇到结构体定义时是否可以看到stdbool.h

我要做一些事情来解决这个问题:

  1. 我要在我的CMake项目中设置一个适当的C标准(我的错)。
  2. 我有一个包装这个库头文件的头文件,因为我为它定义了一些额外的东西。我要添加stdbool.h到这个标题只是以防万一。
  3. 我要向图书馆提交一份PR,加强#ifdef检查。显然,MSVC从VS2013开始支持C99,因此如果定义了_MSC_VER并且至少是1800,则检查可以升级为包括stdbool.h

最新更新