2016-06-06 2 views
2

Я нахожу foo.h файл, имеющий:ли это распространенный способ определения интерфейса в C

typedef STRUCT_s STRUCT; 

STRUCT *foo(); 

и foo.c файл:

#include "i_foo.h" 

struct STRUCT_s{ 
//... 
}; 

#define STRUCT struct STRUCT_s 
STRUCT *foo() 
{ 
    STRUCT *s; 
    //... 
    return s; 
} 

ли это общий способ скрыть определение структуры в C? Если да, то интересно, если структура не объявлена ​​в заголовке, как клиент должен ее использовать?

+1

Это '# define' это * странно, * не говоря уже о ** неправильно ** (из-за полуколония). Но даже когда это удалит, оно останется * странным. * – Angew

+0

Я предлагаю вам заглянуть в [pimpl idiom] (https://en.wikipedia.org/wiki/Opaque_pointer#C) вместо странных хаков вроде этого. –

+0

@Angew Извините, это была моя ошибка. Нет точки с запятой. Это код клиента. Я не уверен, что я пропущу что-то в C, или код является кандидатом-победителем IOCCC –

ответ

3

Это общий способ скрыть определение структуры в C. И клиент не должен использовать структуру напрямую. Он должен использовать только предлагаемые функции из интерфейса для взаимодействия с данными: создавать, устанавливать или получать значения, запускать на нем, ...

Таким образом, реализация полностью скрыта для клиента. Таким образом, клиент не ограничивается изменениями в реализации. Библиотека может развиваться по мере необходимости, не беспокоя клиента, без изменения интерфейса.

+0

OK, хорошо описание. К сожалению, если бы были какие-то функции для работы над STRUCT, я был бы рад. Это «библиотека» разделяемой памяти компании. Но помимо функций create/destroy/size нет другой функции для использования созданного объекта. Я проверил, как они используют его в других проектах, другие разработчики определяют свои собственные структуры и бросают возвращаемый указатель на свои структуры. Я думаю, это не очень хорошо. –

+1

@ValentinHeinitz, вы правы, это нехорошо ... с этим, обычным способом (если я не ошибаюсь), следует добавить функцию в библиотеку, чтобы выделить среди памяти, необходимую этой структуре (в '.h': 'size_t sizeofstruct();' и реализация в '.c' с' sizeof (STRUCT) '). При этом вы можете вызвать распределитель с размером, необходимым библиотеке, не зная реальной структуры. – Garf365

3

Пользователь таким образом не может создать экземпляр структуры и видит объекты этого типа в качестве указателей. Поэтому все конструкторы и методы, геттеры, сеттеры и т. Д. Не понятны пользователю и должны быть определены в источнике библиотеки.

Одним из очевидных дополнительных последствий является то, что при изменении структуры пользователь не должен изменять все свои применения в коде, чтобы инициализировать новые поля или прокомментировать использование несуществующих. Поскольку их не было, их не будет. Внутренняя частная структура структуры полностью скрыта.

+1

Кроме того, нет необходимости перекомпилировать исходные файлы, используя структуру, когда ее реализация изменяется (инкапсуляция). – martinkunev

+0

BTW, гарантирует ли стандарт? Не компиляторы C никогда не используют mangling, и символы в файлах bin гарантированно выглядят так же, как в источнике? – bipll

2

Да, это распространенный способ объявления абстрактного типа данных (ATD). ADT используется только через интерфейс, который представлен функциями, объявленными в файле заголовка. Клиент не имеет доступа к полям напрямую. Также рекомендуется добавить префикс ко всем экспортированным идентификаторам. Это позволяет избежать конфликтов имен и дает понять, откуда приходит импортированный идентификатор.

Пример:

Stacks.h

typedef struct Stacks_StackDesc *Stacks_Stack; 

Stack Stacks_New(void); 

void Stacks_Push(int x, Stacks_Stack s); 

void Stacks_Pop(Stacks_Stack s, int *top); 

Stacks.c

#include "Stacks.h" 

struct Stacks_StackDesc { 
    ... 
}; 

Stack Stacks_New(void) 
{ 
    ... 
} 

void Stacks_Push(int x, Stacks_Stack s) 
{ 
    ... 
} 

void Stacks_Pop(Stacks_Stack s, int *top) 
{ 
    ... 
} 
+0

Префиксы отличаются от пространств имен C++ тем, что вы не можете использовать «Стеки», чтобы сделать небольшую область несколько короче. :( – bipll