Я бы потребовал, чтобы пользователи API вводили «*», то есть typedef для структуры, а не указателя на структуру. Это широко используемый стиль в GLib, который является одним из самых популярных стеков C.
Это хорошо работает, потому что важно знать, есть ли у вас указатель на структуру или на саму структуру. Например, можно ли сохранить NULL в переменной типа? Если вы скрываете, что объект является указателем, вам нужно создать специальный NIL_NODE или другое значение для замены NULL. Если вы просто сделаете его указателем, люди могут относиться к нему как к указателю.
Еще одно важное преимущество - это возможность поместить фактическое определение структуры где-нибудь в частном порядке, то есть в файле .c, а не в заголовке. Вы можете поместить только typedef в заголовок, сохранив при этом саму структуру непрозрачной для пользователей API. Это требует, чтобы люди использовали только те экспортированные методы, которые вы предоставляете для управления структурой. Это также означает, что вам не нужно перестраивать мир, если вы измените поля структуры.
Еще одна причина выбрать этот путь заключается в том, что иногда вам действительно нужна структура, которую можно скопировать, и вы все равно хотите ее определить по типу. Возьмем такую вещь, как GdkPoint:
typedef struct {
int x, y;
} GdkPoint;
Здесь полезно разрешить прямой доступ к структуре, например:
GdkPoint point = { 10, 10 };
GdkPoint copy = point;
do_stuff_with_point(©);
Однако, если вы соглашаетесь, что определение типа «GdkPoint» будет указателем, вам придется действовать непоследовательно.
Код будет более понятным, если вы можете сказать, что является указателем, а что нет, и код лучше инкапсулируется, если вы не помещаете определения структур в заголовок (для структур, которые представляют абстрактные непрозрачные типы данных, что, возможно, является наиболее распространенным своего рода).
Мой шаблон по умолчанию для типа данных C в заголовке выглядит примерно так:
typedef struct MyType MyType;
MyType* my_type_new(void);
void my_type_unref(MyType *t);
void my_type_ref(MyType *t);
Затем фактический "struct MyType" в файле .c вместе с new, unref и любыми операциями с типом.
Исключением будут такие типы, как Point, Rectangle, Color, где требуются «простые старые данные» и прямой доступ к полям; другой вариант - использовать my_type_free () вместо _unref (), если вам не нужен счетчик ссылок.
В любом случае, это один стиль, в основном стиль GLib, который широко используется и, как известно, хорошо работает.
person
Havoc P
schedule
24.02.2011