编辑:将foo_t更改为foo作为类型名称,因为POSIX保留以_t结尾的类型 编辑:将_foo_s更改为foo_s,因为C声明以下划线开头的名称
我对于同时拥有以下内容的最佳方式感到困惑:
我对此的第一次尝试是做以下事情:
foo.h(为简洁省略了包含保护):
typedef struct foo_s foo;
struct foo_s;
foo* foo_create(void);
void foo_do_something(foo *foo);
foo.c的:
#include "foo.h"
struct foo_s {
/* some_hidden_members */
};
foo* foo_create() {
/* allocate memory etc */
}
void foo_do_something(foo *foo) {
/* do something with foo */
}
这似乎适用于gcc。包含foo.h
的每个人只能看到匿名的前向声明,struct foo_s
的真实布局只能在foo.c
中知道。
当我尝试使用include-what-you-use使用clang时,我开始闻到上述奇怪的东西。当我用它来检查foo.c
时,它通知我foo.h
不应包含struct foo_s
的前向声明。我认为这是iwyu中的一个错误,因为对于任何包含foo.h
的人来说,这显然不会有问题。
此时让我从一开始就提出第二个要求。 foo.c
包含foo.h
,以便编译器可以确保foo.h
中声明的每个函数都与foo.c
中的实现相匹配。我想我需要这个,因为我经常遇到分段错误,因为我的实现的函数签名与其他代码使用的头文件中的函数签名不匹配。
后来我尝试用clang编译代码(我用-Wall -Wextra -Werror
编译)并被告知:
error: redefinition of typedef 'foo' is a C11 feature
我不希望我的代码依赖于C11功能,我确实希望确保公共标头中的函数与实现相匹配。我该如何解决?
我看到了将foo.h
分为foo.h
和foo_private.h
的方法:
foo.h(为简洁省略了包含保护):
struct foo_s;
#include "foo_private.h"
foo_private.h(为简洁省略了包含保护):
typedef struct foo_s foo;
foo* foo_create(void);
void foo_do_something(foo *foo);
然后我会在foo_private.h
中加入foo.c
,其他代码会包含foo.h
。这意味着foo.c
不再看到foo_s
的前向声明,因此clang和iwyu应该感到高兴。这也意味着我的函数的实现被检查以匹配标题。
但是虽然这有效,但我想知道这是否是最佳解决方案,因为:
那么解决方案是什么才能满足顶部列出的三个criterea?或者是我找到的解决方案?
答案 0 :(得分:4)
赞赏数据隐藏的崇高意图!
以下情况如何?
foo.h (为简洁省略了包含保护):
typedef struct foo_t foo_t; // note change 0
// note change 1
foo_t* foo_create(void);
void foo_do_something(foo_t *foo);
<强> foo.c的:强>
#include "foo.h"
struct foo_t { // note change 2
/* some_hidden_members */
};
foo_t* foo_create() {
/* allocate memory etc */
}
void foo_do_something(foo_t *foo) {
/* do something with foo */
}