Скрытие определения структуры C - PullRequest
2 голосов
/ 04 декабря 2011

Вот мои настройки:

В публичном .h:

#ifndef PUBLIC_H_
#define PUBLIC_H_

#include "func.h"

/*extern typedef struct _my_private_struct PRIVATE_;*/
typedef struct _my_private_struct PRIVATE_; /* Thanks to larsmans and Simon Richter */
#endif

В struct.h

#ifndef STRUCT_H_
#define STRUCT_H_

struct _my_private_struct {
    int i;
};
#endif

В func.h:

#ifndef FUNC_H_
#define FUNC_H_
#include "struct.h"

/* typedef struct _my_private_struct PRIVATE_; */
extern PRIVATE_ * get_new(int);
#endif

В func.c:

#include <stdlib.h>
#include "func.h"

PRIVATE_ * get_new(int i)
{
    PRIVATE_ *p = (PRIVATE_ *) malloc(sizeof(PRIVATE_));
    if (p == NULL) return NULL;

    p->i = i;

    return p; 
}

В main.c:

#include "public.h"

int main(int argc, char ** argv)
{
    PRIVATE_ *p = get_new(2);
    return 0;
}

Когда я компилирую этот файл с GCC, я получаю эту ошибку:

СТАРШАЯ ОШИБКА КОМПЛЕКТАЦИИ

несколько классов хранения в спецификаторах объявлений

ОШИБКА КОМПЛЕКТАЦИИ ПОСЛЕ РЕДАКТИРОВАНИЯ

ожидается '=', ',', ';', 'asm' или '__attribute__' перед токеном * * '

Может кто-нибудь мне помочь / объяснить, почему я это получаю и как это исправить?

Ответы [ 4 ]

6 голосов
/ 05 декабря 2011

Другие ответы очень хорошо освещают вашу проблему. Тем не менее, позвольте мне добавить к ним и ответить на ваш последний комментарий:

Я получаю ошибку компиляции: в public.h: переопределение typedef PRIVATE _...

Хотя ошибка не требует пояснений, вероятно, не совсем понятно, почему это происходит. Подумайте, что происходит, когда вы включаете public.h:

#include "struct.h"
#include "func.h"
typedef struct _my_private_struct PRIVATE_;

Если вы проследите это и полностью развернете препроцессор, вот что вы получите:

// struct.h
struct _my_private_struct
{
    int i;
};

// func.h
typedef struct _my_private_struct PRIVATE_;
extern PRIVATE_ * get_new(int);

// public.h
typedef struct _my_private_struct PRIVATE_;

Теперь должно быть очевидно, почему вы сталкиваетесь с проблемами. Без typedef в func.h ваш get_new прототип завершится неудачно, потому что он еще не видел PRIVATE. OTOH, если вы оставите typedef в нем, вы определили его дважды.

Кроме того, похоже, что вы пытаетесь сохранить эту структуру изолированной от другого кода и модулей. Даже если вы исправите ошибки сборки, вы не достигли такой инкапсуляции. Учтите это:

int main()
{
    PRIVATE_ *p = get_new(2);
    p->i = 1337;        // HAHA, I just modified your private i.
                        // what are you going to do about it?
}

Если вы хотите конфиденциальности данных в C, рассмотрите непрозрачный дизайн указателя. Я рекомендую реструктурировать ваш источник следующим образом:

// public.h
#ifndef PUBLIC_H_
#define PUBLIC_H_

#include "func.h"

#endif

// func.h
#ifndef FUNC_H_
#define FUNC_H_

struct PRIVATE_NOT_ACCESSIBLE;
typedef struct PRIVATE_NOT_ACCESSIBLE myint_t;

// declare your struct methods here
myint_t* get_new(int);
// ..

#endif

// func.c
#include <stdlib.h>
#include "func.h"

// define this only with functions 
// that's suppose to work with its internal data
struct PRIVATE_NOT_ACCESSIBLE
{
    int i;
};

myint_t * get_new(int i)
{
  // ...
}

Теперь, если вы попробуете это:

#include "public.h"

int main()
{
    myint_t *p = get_new(2);
    p->i = 1337;            // Aw, doesn't work anymore :(
}

Редактировать: Чтобы ответить на комментарий ОП ниже.

Если у вас есть методы приватной структуры, реализованные в более чем одном модуле компиляции, вы все равно можете заставить его работать, перенеся определение приватной команды в выделенный заголовок:

// func_implementation.h
#include "func.h"
struct PRIVATE_NOT_ACCESSIBLE
{
    int i;
};
// internal methods, helper functions you don't want exposed should go here too.
// eg.
void helper_method(myint_t *);

Исходные файлы, которые реализуют ваш struct private 'object', будут включать в себя 'func_implementation.h'. Код внешнего клиента, который использует private, будет включать только func.h.

5 голосов
/ 04 декабря 2011
  • Вы должны завершить оператор typedef ;
  • extern typedef не имеет смысла, просто сделайте typedef.
2 голосов
/ 04 декабря 2011

Текущий синтаксис неверен, вам нужно ставить точку с запятой после typedefs и структур.

1 голос
/ 04 декабря 2011

есть ';' отсутствует после определения типа.

EDIT:

struct _my_private_struct {...};

Не используйте имена с начальным подчеркиванием. Они зарезервированы для языка или реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...