了解将结构转换为void指针

Ale*_*lex 0 c c++

我在Quake 3的渲染库中找到了这段代码.有这个函数:

void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
Run Code Online (Sandbox Code Playgroud)

它在一个循环中被调用,其他一些像这样:

R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
Run Code Online (Sandbox Code Playgroud)

奇怪的部分是poly被声明为srfPoly_t *poly.这里发生了什么?它正在将srfPoly_t对象转换为对象(void *),然后将该函数作为surfaceType_t对象输入.

以下是相关结构的声明:

typedef enum {
  SF_BAD,
  SF_SKIP,        // ignore
  SF_FACE,
  SF_GRID,
  SF_TRIANGLES,
  SF_POLY,
  SF_MD3,
  SF_MD4,
  SF_FLARE,
  SF_ENTITY,        // beams, rails, lightning, etc that can be determined by entity
  SF_DISPLAY_LIST,

  SF_NUM_SURFACE_TYPES,
  SF_MAX = 0x7fffffff     // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;

typedef struct srfPoly_s {
  surfaceType_t surfaceType;
  qhandle_t   hShader;
  int       fogIndex;
  int       numVerts;
  polyVert_t    *verts;
} srfPoly_t;
Run Code Online (Sandbox Code Playgroud)

这是在C中工作,但我试图在C++中实现类似的东西,但我收到以下错误:

Error   1   error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
Run Code Online (Sandbox Code Playgroud)

看来我无法在C++中执行这种类型的强制转换,或者可能还有其他一些我无法理解的东西.我对C++不是很熟悉,并且很想知道如何使用它来设置类似的东西.

我假设这与C++中的类型检查有关,所以不允许这样做.如何以安全的方式在C++中实现类似的东西?

Ale*_*man 5

这在C中有效,因为结构只是内存块,结构中的每个元素都是连续布局的.这种转换是有效的,因为结构的第一个n字节由该srfPoly_t结构中的surfaceType_t枚举组成.被调用的函数试图将传入解释srfPoly_t为a surfaceType_t,并且成功,因为n参数的第一个字节实际上是a surfaceType_t.没有充分理由不要这样做.

来自void*C的转换不会像在C中那样自动发生在C++中.您可以使用reinterpret_cast在两种不同类型的结构之间显式转换:

srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);
Run Code Online (Sandbox Code Playgroud)

  • 哎呀,我忘了从指针投射到指针.谢谢你的帮助 - 我编辑了我的答案以反映这一点. (2认同)