Один из способов сделать это — показать общий размер непрозрачного типа и заставить его объявить объекты вашего непрозрачного типа как unsigned char [N]
буферы. Например, допустим, у вас есть некий тип OpaqueType
, внутренности которого вы хотите скрыть от пользователя.
В заголовочном файле (представленном пользователю) вы делаете это
typedef unsigned char OpaqueType[16];
где 16
— это точный размер в байтах типа, который вы хотите скрыть. В заголовочном файле вы пишете весь интерфейс с точки зрения этого типа, например.
void set_data(OpaqueType *dst, int data);
В файле реализации вы объявляете фактический тип
typedef struct OpaqueTypeImpl
{
int data1;
double data2;
} OpaqueTypeImpl;
и реализовать функции следующим образом
void set_data(OpaqueType *dst, int data)
{
OpaqueTypeImpl *actual_dst = (OpaqueTypeImpl *) dst;
actual_dst->data1 = data;
}
Вы также можете добавить статическое утверждение, которое будет гарантировать, что sizeof(OpaqueType)
совпадает с sizeof(OpaqueTypeImpl)
.
Конечно, как было отмечено в комментариях ниже, необходимо предпринять дополнительные шаги, чтобы обеспечить правильное выравнивание таких объектов, например _Alignas
в C11 или какую-либо технику на основе объединения в «классическом» C.
Таким образом, вы даете пользователю возможность объявить нединамический объект OpaqueType
, то есть вы не заставляете пользователя вызывать вашу функцию, которая будет malloc
таких объектов внутри. И в то же время вы ничего не показываете пользователю о внутренней структуре вашего типа (кроме его общего размера и требований к выравниванию).
Также обратите внимание, что OpaqueType
, объявленный таким образом, является массивом, а это означает, что его нельзя скопировать (если только вы не используете memcpy
). Это может быть полезно, если вы хотите активно предотвращать неограниченное копирование на уровне пользователя. Но если вы хотите включить копирование, вы можете обернуть массив в структуру.
Этот подход не слишком элегантен, но это, вероятно, единственный способ скрыть реализацию, когда вы хотите, чтобы объекты вашего типа свободно определялись пользователем.
person
AnT
schedule
06.07.2015
malloc
имеет к области видимости typedefs?! - person ikegami   schedule 06.07.2015typedef
в файлах .c, которые определяют конкретный набор вызовов функций. - person chux - Reinstate Monica   schedule 06.07.2015Malloc
не имеет абсолютно никакого отношения к конфиденциальности. На самом деле, C сам по себе не позволяет делать вещи приватными, хотя вы можете попытаться сделать их непрозрачными. - person David Hoelzer   schedule 06.07.2015bit_typ
должен быть доступен только как предварительное объявлениеtypedef struct bit_typ bit_typ;
- типичный непрозрачный typedef. К сожалению, это не позволяет пользователю определять объекты типаbit_typ
. Пользователь должен вызвать функцию API (которая знает все оbit_typ
), котораяmalloc
изменит объект. Этоmalloc
, о котором говорит OP, и поэтому его часто упоминают в связи с непрозрачными типами.malloc
— это цена, которую мы должны заплатить за полную непрозрачность. Обойти это невозможно, если только вы не пойдете так, как я описываю ниже. - person AnT   schedule 06.07.2015