假设您正在编写一个在内部使用某些数据结构的库,并希望仅向用户导出它们的一部分(或使用void *
之类的内容隐藏确切的类型)。库中使用的所有结构和函数的定义都在标题library.h
中,将在构建库时使用。
在构建过程中不会使用library.h
的另一个副本,但仅限于链接到库的用户,是否认为这是一种好的做法?
例如,假设库内部使用以下library.h
:
#ifndef LIBRARY_H
#define LIBRARY_H
struct myStruct {
int some_x;
void (*some_callback)(void);
};
typedef struct myStruct *myStruct_t;
#endif
虽然我们希望向用户隐藏myStruct
的定义,但我们导出的标题为library.h
:
#ifndef LIBRARY_H
#define LIBRARY_H
typedef void *myStruct_t;
#endif
答案 0 :(得分:2)
在构建过程中不会使用的另一个library.h副本是否被认为是一种良好的做法,但仅限于链接到库的用户?
没有。虽然您想要做的最佳实践的细节可能是一个品味问题,但在构建过程中提供未使用的标题客观上并不是一个好习惯:您可能会引入在构建项目时从未捕获的输入错误。< / p>
所以,如果不详细说明你应该如何组织,那么你应该做的就是让每个&#34; 私人&#34;标题#include
各自的&#34; 公开&#34;标头,不重复私有标头中的公共声明。对于您的示例,这将看起来例如像:
<强> library.h:强>
#ifndef LIBRARY_H
#define LIBRARY_H
typedef struct myStruct *myStruct_t;
// there's absolutely no need to use void * here. An incomplete struct
// type is perfectly fine as long as only pointers to it are used.
#endif
<强> library_internal.h:强>
#ifndef LIBRARY_INTERNAL_H
#define LIBRARY_INTERNAL_H
#include "library.h"
struct myStruct {
int some_x;
void (*some_callback)(void);
};
#endif
其他&#34;最佳做法&#34;注意到:
不要隐藏typedef
后面的指针。大多数C程序员都清楚地知道指针是声明符的一部分,并且希望在有指针时显式地看指针。取消引用不像指针一样外观的东西只会引起其他人阅读代码的混淆。您也可能会混淆图书馆的消费者,希望myStruct_t
能够展示按值调用语义。
不要使用_t
后缀定义自己的类型。至少在POSIX中,这是为(编译器/运行时)的实现保留的。定义与struct
标记相同名称的类型并没有错。
这些额外建议的示例:
<强> library.h:强>
#ifndef LIBRARY_H
#define LIBRARY_H
typedef struct myStruct myStruct;
#endif
<强> library_internal.h:强>
#ifndef LIBRARY_INTERNAL_H
#define LIBRARY_INTERNAL_H
#include "library.h"
struct myStruct {
int some_x;
void (*some_callback)(void);
};
#endif
答案 1 :(得分:2)
请注意,C标准不保证指向void的指针具有与指向结构的指针兼容的表示!因此:
typedef struct myStruct *myStruct_t;
typedef void *myStruct_t;
这两者不兼容,不能用于严格遵守的程序。
另一件事是你通常不应该隐藏指针,除非需要。例如,考虑标准库中的FILE
。它的内容没有在任何地方定义,但所有函数都专门为它返回一个指针并接受一个指针。
您甚至可以使用简单的struct
声明,而不是定义:
struct myStruct;
然后外部用户可以定义变量作为指向它的指针
struct myStruct *handle;
或者,如果您希望隐藏它确实是结构的事实,请使用typedef
:
typedef struct myStruct myStruct;
然后外部接口的用户可以简单地将其变量定义为
myStruct *handle;