标题中的匿名前向声明冲突

jos*_*sch 5 c gcc c99 clang forward-declaration

编辑:将foo_t更改为foo作为typename,因为POSIX保留以_t EDIT结尾的类型:将_foo_s更改为foo_s,因为C声明以下划线开头的名称

我很困惑,最好的方法是同时拥有以下内容:

  1. 库实现可以看到struct成员,但库的用户却看不到
  2. 编译器检查标头中的函数定义是否与实现匹配
  3. 使用C99

我对此的第一次尝试是做以下事情:

foo.h(为简洁省略包含保护):

typedef struct foo_s foo;

struct foo_s;

foo* foo_create(void);
void foo_do_something(foo *foo);
Run Code Online (Sandbox Code Playgroud)

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

这似乎与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
Run Code Online (Sandbox Code Playgroud)

我不希望我的代码依赖于C11功能,我确实希望确保公共头中的函数与实现相匹配.我该如何解决?

我看到一个办法是分裂foo.hfoo.hfoo_private.h:

foo.h(为简洁省略包含保护):

struct foo_s;

#include "foo_private.h"
Run Code Online (Sandbox Code Playgroud)

foo_private.h(为简洁省略了包含保护):

typedef struct foo_s foo;

foo* foo_create(void);
void foo_do_something(foo *foo);
Run Code Online (Sandbox Code Playgroud)

然后,我将包括foo_private.hfoo.c和其他代码将包括foo.h.这意味着foo.c不再看到前方声明,foo_s因此clang和iwyu应该感到高兴.这也意味着我的函数的实现被检查以匹配标题.

但是虽然这有效,但我想知道这是否是最好的解决方案,因为:

  • 有一个头文件只有两行似乎是浪费
  • 我不知道其他项目那样做(并查看我的/ usr/include我也看不到任何)

那么解决方案是什么才能满足顶部列出的三个criterea?或者是我找到的解决方案?

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

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