首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >头中相互冲突的匿名转发声明

头中相互冲突的匿名转发声明
EN

Stack Overflow用户
提问于 2014-09-19 17:39:10
回答 1查看 1K关注 0票数 5

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

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

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

我第一次尝试这样做是为了做以下工作:

foo.h (为了简洁起见省略了包含警卫):

代码语言:javascript
复制
typedef struct foo_s foo;

struct foo_s;

foo* foo_create(void);
void foo_do_something(foo *foo);

F.c:

代码语言:javascript
复制
#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的包含-什么-你-使用时,我开始用上面提到的奇怪的东西。当我使用它检查foo.c时,它告诉我foo.h不应该包含struct foo_s的前向声明。我认为这是iwyu中的一个bug,因为显然这对包括foo.h的其他任何人来说都不是问题。

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

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

代码语言:javascript
复制
error: redefinition of typedef 'foo' is a C11 feature

我不希望我的代码依赖于C11特性,我确实希望确保公共标题中的函数与实现匹配。我该怎么解决呢?

我看到了一种将foo.h分解成foo.hfoo_private.h的方法

foo.h (为了简洁起见省略了包含警卫):

代码语言:javascript
复制
struct foo_s;

#include "foo_private.h"

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

代码语言:javascript
复制
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应该很高兴。这还意味着检查我的函数的实现以匹配标头。

但是,虽然这是可行的,但我想知道这是否是最好的解决办法,因为:

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

那么,怎样的解决方案才能满足上面列出的三个标准呢?还是我找到了解决办法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-19 18:10:57

荣誉对数据隐藏的崇高意图!

下面这个怎么样?

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

代码语言:javascript
复制
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:

代码语言:javascript
复制
#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 */
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25939478

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档