I'm hiding some struct fields from struct types to make public API headers more clear.
First I used this style to hide (not actually hide, just separate from public editable members) some members,
include/scene.h
typedef struct ScenePrivateFields {
  SceneFlags flags;
  /* other members */
} ScenePrivateFields;
typedef struct Scene {
  ScenePrivateFields _priv;
  RootNode           rootNode;
  /* other members */
} Scene;
with this style I always use Scene type in function parameters then accessing private fields using _priv member. But keeping all private fields in public header makes header more complex
Eventually I switched to another style
include/scene.h
typedef struct Scene {
  RootNode rootNode;
  /* other members */
} Scene;
EXPORT
Scene*
allocScene(void);
src/types/impl_scene.h
typedef struct SceneImpl {
  Scene      pub;
  SceneFlags flags;
  /* other members */
} SceneImpl;
for instance if I have a function like this:
include/scene.h
void
renderScene(Scene * __restrict scene, /* other params */);
I have to cast scene to SceneImpl to access private fields. I'm doing this like:
src/scene/scene.c
void
renderScene(Scene * __restrict scene, /* other params */) {
  SceneImpl *sceneImpl;
  sceneImpl = (SceneImpl *)scene;
}
to avoid casting every function call I thought that maybe I can do something like this, if it is legal and not violating C standards:
src/scene/scene.c
void
renderScene(SceneImpl * __restrict sceneImpl, /* other params */) {
  /* skip casting scene to sceneImpl */
}
Since Scene is first member of SceneImpl, Can I define public api (function) with Scene and define implementation (function) with SceneImpl. I think it would work because both are pointer, is it valid or good idea?
NOTE: I'm compiling with -fstrict-aliasing
EDIT: FWIW, Here alloc function implementation, users must use this func to alloc struct:
EXPORT
Scene*
allocScene(void) {
  SceneImpl *sceneImpl;
  sceneImpl = calloc(1, sizeof(*sceneImpl));
  /* initialize pulic part */
  sceneImpl->pub.field1 = ...
    /* initialize private part */
  sceneImpl->priv_field1 = ...
  /* return public part */
  return &sceneImpl->pub;
}
 
     
    