header 中的匿名前向声明冲突

标签 c gcc clang c99 forward-declaration

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

我对同时拥有以下内容的最佳方法感到困惑:

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

我的第一个尝试是执行以下操作:

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 中已知.

当我尝试使用使用 clang 的 include-what-you-use 时,我开始闻到上面的内容有些奇怪。当我用它来检查 foo.c它告诉我foo.h不应包含 struct foo_s 的前向声明.我认为这是 iwyu 中的一个错误,因为显然这对包含 foo.h 的任何其他人来说都不是问题。 .

在这一点上让我从头开始我的第二个要求。 foo.c包括 foo.h以便编译器可以确保在 foo.h 中声明的每个函数匹配 foo.c 中的实现.我认为我需要这个,因为我经常遇到段错误,因为我的实现的函数签名与其他代码使用的 header 中的签名不匹配。

后来我尝试用 clang 编译代码(我用 -Wall -Wextra -Werror 编译)并被告知:

error: redefinition of typedef 'foo' is a C11 feature

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

我看到一种方法是拆分foo.h进入foo.hfoo_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.hfoo.c和其他代码将包括 foo.h .这意味着 foo.c没有看到 foo_s 的前向声明clang 和 iwyu 应该会很高兴。这也意味着检查我的函数的实现以匹配 header 。

但是虽然这可行,但我想知道这是否是最佳解决方案,因为:

  • 一个头文件只有两行似乎是一种浪费
  • 我不知道有其他项目是这样做的(在我的/usr/include 中我也没有看到)

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

最佳答案

对数据隐藏的崇高意图表示敬意!

下面的怎么样?

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 */
}

关于 header 中的匿名前向声明冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25939478/

相关文章:

c++ - 为什么 GCC 的 std::function 不使用对按值传递的参数的右值引用在其内部委托(delegate)之间传递它们?

c - 如何保存 clang AST?

c++ - 当 `delete` 使用非虚析构函数处理基类时,Clang 和 GCC 会做什么?

c - 如何使用队列计算二叉树中叶节点的数量?

c++ - 较新版本的 GCC 抛出 reinterpret_cast 错误

linux - 如何将版本信息嵌入到共享库和二进制文件中?

C++Builder 10.2 基于函数的优化状态 "unknown attribute ' optimize' ignored"

c - "Hacking: The Art of Exploitation": why does example program work with just gcc but not with -m32?

使用fifos的客户端服务器,发送突发和接收处理时间

c - 从进程中取消绑定(bind)击键