Alex
Alex

Reputation: 1233

Understanding casting a struct as a void pointer

I found this code in the rendering library for Quake 3. There is this function:

void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`

It is being called in a loop somehwere else like this:

R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );

The weird part is that poly was declared as srfPoly_t *poly. What is going on here? It is casting a srfPoly_t object to (void *) and then entering the function as a surfaceType_t object.

Here are the declaration for the relevant structs:

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;

This is working in C, but I am trying to implement something similar in C++, but I get the following error:

Error   1   error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'

It would appear I cannot perform this type of cast in C++, or maybe there is something else I am unable to understand. I am not very familiar with C++ and would love to figure out how to set up something similar using it.

I am assuming this has something to do with type checking in C++, so it is not allowed. How can I implement something similar in C++ in a safe way?

Upvotes: 1

Views: 4467

Answers (1)

Alex Kleiman
Alex Kleiman

Reputation: 709

This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.

Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:

srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);

Upvotes: 6

Related Questions