2012-02-13 2 views
0

У меня есть .c файл (библиотека функций) с функцией и определение так:Скрыть определение типа в C

typedef long double big; 
big foo(int x) { ... } 

Я хочу создать интерфейс этой библиотеки, в .h. Так что я делаю:

typedef long double big; 
big foo(int); 

и удалить typedef long double big; из файла .c. Но тем самым я даю определение типа big в моем интерфейсе, поэтому это не чистый интерфейс. Любые идеи, как это исправить?

Я знаю, что я мог бы сделать это в моем .c файле:

struct foo { 
    long double; 
}; 

, а затем в файле .h сделать:

typedef struct foo big; 
big foo(int); 

Но, похоже, отходы создать struct только для одного поля, плюс я должен использовать оператор . всякий раз, когда я хочу прочитать big.

ответ

4

Если тип никогда не будет более сложным, чем 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. Основная проблема здесь - убедиться, что вы знаете, как обрабатываются распределения памяти.

Иногда эта техника стоит того. Часто это не обязательно. Вам нужно будет сделать оценку для себя.

+0

Мне бы очень хотелось избежать использования 'struct', как я писал в моем вопросе, нет ли другого пути? –

+0

Нет, я не верю, что есть альтернатива - если вы не сосчитаете 'union' как альтернативу' struct'. Ну, есть старый резерв 'void *', но это намного хуже, чем неполный тип структуры. Если вы действительно хотите получить ужас, вы можете позволить пользователям подумать: «О, это тип структуры», в то время как в вашем коде вы делаете 'long double * my_value = (long double *) big_t_pointer_from_interface;'. Если вы хотите улучшить абстракцию, используйте C++, но вы будете определять класс на C++, если вы это сделаете, поэтому мы вернемся к квадрату. Нет, нет реальной альтернативы определению структуры. –

+0

Одним из преимуществ непрозрачного (структурного) типа является то, что он дает лучший запас безопасности, чем использование 'void *'; ваш компилятор будет жаловаться, если пользователь передает указатель на 'int' или указатель на' double', где 'big_t *' ожидается, если 'big_t' является непрозрачным. Если 'big_t *' является псевдонимом для 'void *', то вы можете передать любой старый указатель в функцию. –

2

и удалите длинный двойной длинный длинный; из .c файла. Но тем самым я даю определение типа большого в моем интерфейсе, поэтому это не чистый интерфейс.

Как это сделать? Кто заботится, могут ли пользователи вашего кода видеть typedef? Как это больно ... что-нибудь? Им нужен способ использования вашего typedef, и так оно и делается. Звучит как теоретическая проблема для меня, которая не имеет ощутимых побочных эффектов. Вы беспокоитесь о неправильных вещах.

Но тит кажется пустой, чтобы создать структуру только для одного поля, плюс я должен использовать. когда я хочу читать большой.

Да, это глупо. Кроме того, теперь вы отдали определение своей структуры! о нет! Как это иначе, чем разоблачение typedef (или любого другого типа)?

+0

Я забочусь! Если пользователь видит 'long double', возможно, он начинает использовать' long double', а не 'big', скажем так, и через некоторое время я хотел бы использовать' big' для 'char *'. Тогда код пользователя не будет работать. Говоря 'typedef struct foo big;' Я не выдаю определение моей 'struct', пользователь не может знать, какие поля' struct foo'. –

+2

Это не ваша проблема. Это проблема пользователя, потому что они отказались использовать ваш API. –

+0

@DavidBrown Я не думаю, что это правильный аргумент. Например. вы можете определить все свои поля в классе Java как 'public' и просто сказать пользователю ** не использовать поля **, не кажется правильным способом создания API (выдача ** внутри * * информация о нем). –

Смежные вопросы