Если тип никогда не будет более сложным, чем long double
, то, вероятно, не стоит иметь притязаний на его укрытие. Если это может потребоваться, чтобы стать более сложным, вы можете рассмотреть использование непрозрачного типа. В общедоступном заголовке, big.h
, вы используете:
#ifndef BIG_H_INCLUDED
#define BIG_H_INCLUDED
typedef struct big big_t;
extern big_t *foo(int);
...
#endif
Все функции будут принимать и возвращать указатели на big_t
типа. Это все, что вы можете сделать с такими неполными типами. Обратите внимание, что ваши клиенты не могут выделять значения big_t
для себя; они не знают, насколько большой тип. Это означает, что вы, вероятно, в конечном итоге с такими функциями, как:
extern big_t *big_create(void);
extern void big_destroy(big_t *value);
создавать и уничтожать big_t
значения. Тогда они будут иметь возможность выполнять арифметические действия с:
extern big_errno_t big_add(const big_t *lhs, const big_t *rhs, big_t *result);
и т.д., но потому, что они имеют только непрозрачный неполный тип, они не могут надежно идти Мессинг вокруг внутри big_t
структуры.Но учтите, что вы ограничены использованием указателей в интерфейсе. Для передачи или возврата значений требуются полные типы, и если тип завершен, пользователи могут исследовать его внутреннюю работу.
В заголовке реализации, bigimpl.h
, вы будете иметь:
#ifndef BIGIMPL_H_INCLUDED
#define BIGIMPL_H_INCLUDED
#include "big.h"
struct big
{
...whatever the details actually are...
};
#endif
И ваш код реализации будет включать в себя только bigimpl.h
, но включает в себя big.h
. Основная проблема здесь - убедиться, что вы знаете, как обрабатываются распределения памяти.
Иногда эта техника стоит того. Часто это не обязательно. Вам нужно будет сделать оценку для себя.
Мне бы очень хотелось избежать использования 'struct', как я писал в моем вопросе, нет ли другого пути? –
Нет, я не верю, что есть альтернатива - если вы не сосчитаете 'union' как альтернативу' struct'. Ну, есть старый резерв 'void *', но это намного хуже, чем неполный тип структуры. Если вы действительно хотите получить ужас, вы можете позволить пользователям подумать: «О, это тип структуры», в то время как в вашем коде вы делаете 'long double * my_value = (long double *) big_t_pointer_from_interface;'. Если вы хотите улучшить абстракцию, используйте C++, но вы будете определять класс на C++, если вы это сделаете, поэтому мы вернемся к квадрату. Нет, нет реальной альтернативы определению структуры. –
Одним из преимуществ непрозрачного (структурного) типа является то, что он дает лучший запас безопасности, чем использование 'void *'; ваш компилятор будет жаловаться, если пользователь передает указатель на 'int' или указатель на' double', где 'big_t *' ожидается, если 'big_t' является непрозрачным. Если 'big_t *' является псевдонимом для 'void *', то вы можете передать любой старый указатель в функцию. –