Search code examples
cpointerscasting

Is it allowed to cast a pointer of first member to the enclosing type?


According to the C Standard, it is allowed to cast a pointer to a struct to a pointer of the type of the first member of this struct. However, is it allowed to do the opposite?

Consider the following example:

//texture.h
typedef struct HAL_TEXTURE {
  size_t w;
  size_t h;
} HAL_TEXTURE;

HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data);
void BindTexture(HAL_TEXTURE* texture);
// d3d10/texture.c linked on windows
typedef struct D3D10_TEXTURE { // not visible outside of this translation unit
  HAL_TEXTURE agnostic;
  ID3D10ShaderResourceView* srv;
} D3D10_TEXTURE;

HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data) {
  D3D10_TEXTURE* texture = calloc(...);
  //...//
  return (HAL_TEXTURE*)texture; // ok, according to standard
}

void BindTexture(HAL_TEXTURE* texture) {
  D3D10_TEXTURE* tex = (D3D10_TEXTURE*)texture; // is this allowed?
  //...//
  //access D3D10 specific stuff here
}
// ogl/texture.c linked on linux
typedef struct OGL_TEXTURE { // not visible outside of TU
  HAL_TEXTURE agnostic;
  GLint id;
} OGL_TEXTURE;

HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data) {
  OGL_TEXTURE* texture = calloc(...);
  //...//
  return (HAL_TEXTURE*)texture;
}

void BindTexture(HAL_TEXTURE* texture) {
  OGL_TEXTURE* tex = (OGL_TEXTURE*)texture;
  //...//
  //access OpenGL specific stuff here
}

Can I safely cast HAL_TEXTURE* (which is the first member of D3D10_TEXTURE and OGL_TEXTURE) to a pointer of the enclosing type?


Solution

  • Yes. According to the ISO C standard (C2x working draft from 2019) (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2347.pdf), section 6.7.2.1 §15:

    1. Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.