Я скрываю некоторые поля структуры из типов struct, чтобы сделать заголовки общедоступного API более понятными.
Сначала я использовал этот стиль, чтобы скрыть (на самом деле не скрывать, просто отделить от общедоступных редактируемых элементов) некоторые элементы,
include/scene.h
typedef struct ScenePrivateFields {
SceneFlags flags;
/* other members */
} ScenePrivateFields;
typedef struct Scene {
ScenePrivateFields _priv;
RootNode rootNode;
/* other members */
} Scene;
в этом стиле я всегда использую тип сцены в параметрах функции, а затем получаю доступ к закрытым полям с помощью члена _priv. Но сохранение всех закрытых полей в общедоступном заголовке делает заголовок более сложным.
В конце концов я перешел на другой стиль
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;
например, если у меня есть такая функция:
include/scene.h
void
renderScene(Scene * __restrict scene, /* other params */);
Мне нужно передать сцену в SceneImpl, чтобы получить доступ к закрытым полям. Я делаю это так:
src/scene/scene.c
void
renderScene(Scene * __restrict scene, /* other params */) {
SceneImpl *sceneImpl;
sceneImpl = (SceneImpl *)scene;
}
чтобы избежать приведения каждого вызова функции, я подумал, что, возможно, я смогу сделать что-то вроде этого, если это законно и не нарушает стандарты C:
src/scene/scene.c
void
renderScene(SceneImpl * __restrict sceneImpl, /* other params */) {
/* skip casting scene to sceneImpl */
}
Поскольку Scene является первым членом SceneImpl, могу ли я определить общедоступный api (функцию) с помощью Scene и определить реализацию (функцию) с помощью SceneImpl. Я думаю, это сработает, потому что оба являются указателями, это правильная или хорошая идея?
ПРИМЕЧАНИЕ: я компилирую с -fstrict-aliasing
РЕДАКТИРОВАТЬ: FWIW, здесь реализация функции выделения, пользователи должны использовать эту функцию для выделения структуры:
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;
}