Скрытие определения структуры C

Вот моя установка:

В public.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 ответа

Решение

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

Я получаю ошибку компиляции: в 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 :(
}

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

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

// 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.

  • Вы должны закончить typedef заявление с ;
  • extern typedef не имеет смысла, просто сделать typedef,

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

E сть ';' отсутствует после typedef.

РЕДАКТИРОВАТЬ:

struct _my_private_struct {...};

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

Другие вопросы по тегам