隐藏C结构定义

mar*_*kfw 2 c oop struct compiler-errors data-hiding

这是我的设置:

在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
Run Code Online (Sandbox Code Playgroud)

在struct.h中

#ifndef STRUCT_H_
#define STRUCT_H_

struct _my_private_struct {
    int i;
};
#endif
Run Code Online (Sandbox Code Playgroud)

在func.h中:

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

/* typedef struct _my_private_struct PRIVATE_; */
extern PRIVATE_ * get_new(int);
#endif
Run Code Online (Sandbox Code Playgroud)

在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; 
}
Run Code Online (Sandbox Code Playgroud)

在main.c中:

#include "public.h"

int main(int argc, char ** argv)
{
    PRIVATE_ *p = get_new(2);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我用GCC编译这些文件时,我收到此错误:

旧的编译错误

声明说明符中的多个存储类

编辑后的编译错误

在'*'标记之前预期'=',',',';','asm'或'__attribute__'

有人可以帮助我/解释为什么我得到这个以及如何解决它?

gre*_*olf 6

其他答案很好地解决了你的问题.但是,请允许我添加并回答您的最新评论:

我收到编译错误:在public.h中:重新定义typedef PRIVATE _...

虽然错误是不言自明的,但可能不太清楚为什么会发生这种情况.考虑一下当你包含public.h时会发生什么:

#include "struct.h"
#include "func.h"
typedef struct _my_private_struct PRIVATE_;
Run Code Online (Sandbox Code Playgroud)

如果你追踪并完全展开预处理器,这就是你将得到的:

// 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_;
Run Code Online (Sandbox Code Playgroud)

现在应该很明显为什么你遇到了问题.如果没有func.h中的typedef,你的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?
}
Run Code Online (Sandbox Code Playgroud)

如果您想在C中使用数据隐私,请考虑使用不透明的指针设计.我建议像这样重构你的来源:

// public.h
#ifndef PUBLIC_H_
#define PUBLIC_H_

#include "func.h"

#endif
Run Code Online (Sandbox Code Playgroud)
// 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
Run Code Online (Sandbox Code Playgroud)
// 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)
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,如果你试试这个:

#include "public.h"

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

编辑:回答以下OP的评论.

如果您在多个编译单元中实现了私有结构的方法,您仍然可以通过将私有定义移动到专用标头来使其工作:

// 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 *);
Run Code Online (Sandbox Code Playgroud)

实现struct private'object'的源文件将包含'func_implementation.h'.使用私有的外部客户端代码仅包含'func.h'.

  • @markfw我已经编辑了我如何做到这一点的答案. (2认同)

Fre*_*Foo 5

  • 你必须typedef用a 结束陈述;
  • extern typedef没有意义,只是做一个typedef.

  • 详细说明,`typedef`是一个存储类,类似于`extern`和`static`.编译器抱怨您正在将多个存储类应用于一个定义. (2认同)