Обычная техника такова:
/* foo.h */
typedef struct Foo Foo;
Foo *foo_create(...);
void foo_bark(Foo* foo, double loudness);
/* foo.c */
struct Foo {
int private_var;
};
Вы можете частично скрыть элементы данных, определив Foo в заголовке и FooPrivate в файле .c, таким образом:
struct FooPrivate {
Foo public_stuff;
int private_var;
}
Но тогда ваша реализация должна переключаться между Foo и FooPrivate, который я считаю королевским PITA, и это бремя обслуживания, если вы передумаете позже и захотите сделать что-то личное. Если вы не хотите высосать каждый последний цикл процессора из кода, просто используйте функции доступа.