C не имеет механизма скрытия отдельных элементов типа конструкции. Однако, действуя только с точки зрения указателей на такой тип и не предоставляя определения, вы можете сделать весь тип непрозрачным. Пользователи должны будут использовать предоставляемые вами функции для манипулирования экземплярами любым способом. Это то, что иногда делается.
В некоторой степени вы можете достичь чего-то похожего на то, что вы описываете в скрытом контексте. Например, рассмотрим это:
header.h
typedef struct _person {
float wage;
int groupid;
} Person;
implementation.c
struct _person_real {
Person person; // must be first, and is a structure, not a pointer.
int id;
char name[NAME_MAX_LEN];
};
Теперь вы можете сделать это:
Person *create_person(char name[]) {
struct _person_real *pr = malloc(sizeof(*pr));
if (pr) {
pr->person.wage = DEFAULT_WAGE;
pr->person.groupid = DEFAULT_GROUPID;
pr->id = generate_id();
strncpy(pr->name, name, sizeof(pr->name));
pr->name[sizeof(pr->name) - 1] = '\0';
return &pr->person; // <-- NOTE WELL
} else {
return NULL;
}
}
Указатель на первый член структуры всегда также указывает на всю структуру, поэтому, если клиент передает вам указатель, полученный из этой функции, вы можете
struct _person_real *pr = (struct _person_real *) Person_pointer;
и работа над членами из более широкого контекста.
Однако следует помнить, что такая схема рискованна. Ничто не мешает пользователю создать Person
без большего контекста и передать указатель на него функции, которая ожидает присутствия объекта контекста. Есть и другие проблемы.
В целом, C API, как правило, либо используют подход непрозрачной структуры, либо просто тщательно документируют, что клиентам разрешено делать с данными, к которым у них есть доступ, или даже просто документируют, как все работает, чтобы пользователи могли сами выбирать. Они, особенно последние, хорошо согласуются с общими подходами и идиомами С - С не держит вас за руку и не защищает от причинения вреда. Вам доверяют знать, что вы делаете, и делать только то, что вы собираетесь делать.