Наименее мрачное решение, которое я видел в этом, состояло в том, чтобы предоставить непрозрачную структуру для использования вызывающей стороной, которая является достаточно большой, плюс, возможно, немного, наряду с упоминанием типов, используемых в реальной структуре, чтобы гарантироватьчто непрозрачная структура будет выровнена достаточно хорошо по сравнению с реальной:
struct Thing {
union {
char data[16];
uint32_t b;
uint8_t a;
} opaque;
};
typedef struct Thing Thing;
Затем функции берут указатель на один из них:
void InitThing(Thing *thing);
void DoThingy(Thing *thing,float whatever);
Внутренне, не раскрывается как частьAPI, есть структура, которая имеет истинные внутренние компоненты:
struct RealThing {
uint32_t private1,private2,private3;
uint8_t private4;
};
typedef struct RealThing RealThing;
(у этого просто есть uint32_t' and
uint8_t '- вот причина появления этих двух типов в объединении выше.)
Плюс, вероятно, утверждение времени компиляции, чтобы убедиться, что размер RealThing
не превышает размер Thing
:
typedef char CheckRealThingSize[sizeof(RealThing)<=sizeof(Thing)?1:-1];
Тогда каждая функция в библиотеке выполняетприведите его аргумент, когда он собирается его использовать:
void InitThing(Thing *thing) {
RealThing *t=(RealThing *)thing;
/* stuff with *t */
}
С этим на месте вызывающая сторона может создавать объекты нужного размера в стеке и вызывать функции для них, структура по-прежнему непрозрачна,и есть некоторыепроверка того, что непрозрачная версия достаточно велика.
Одна потенциальная проблема заключается в том, что поля могут быть вставлены в реальную структуру, что означает, что требуется выравнивание, а не непрозрачная структура, и это не обязательно отключитпроверка размераМногие такие изменения изменят размер структуры, поэтому их поймают, но не все.Я не уверен в каком-либо решении этого вопроса.
В качестве альтернативы, если у вас есть специальные общедоступные заголовки, которые библиотека никогда не включает в себя, то вы, вероятно, можете (при условии тестирования на компиляторах, которые выподдержка ...) просто напишите свои публичные прототипы с одним типом и ваши внутренние с другим.Тем не менее, было бы неплохо структурировать заголовки так, чтобы библиотека каким-то образом видела общедоступную структуру Thing
, чтобы можно было проверить ее размер.