C 定义之前是否允许使用typedef

C 定义之前是否允许使用typedef,c,clang,iwyu,C,Clang,Iwyu,最低代码: //foo.h typedef struct foo_s foo_t; 结构foo\u s{ foo_t*next; }; iwyu坚持在我typedef将其转发到foo\u t之前,我先声明struct foo\u s 输出: $iwyu-cfoo.h foo.h应添加以下行: 结构foo_s; foo.h应删除以下行: foo.h的完整包含列表: 结构foo_s; --- 这在不同版本的iwyu中都是如此,包括添加了-Xiwyu--no_fwd_decls的较新版本 这是iw

最低代码:

//foo.h
typedef struct foo_s foo_t;
结构foo\u s{
foo_t*next;
};
iwyu
坚持在我
typedef
将其转发到
foo\u t
之前,我先声明
struct foo\u s

输出:

$iwyu-cfoo.h
foo.h应添加以下行:
结构foo_s;
foo.h应删除以下行:
foo.h的完整包含列表:
结构foo_s;
---
这在不同版本的
iwyu
中都是如此,包括添加了
-Xiwyu--no_fwd_decls
的较新版本

这是
iwyu
中的错误还是
C
标准要求我在
typedef
之前定义类型

C标准是否希望我在
typedef
之前定义类型

事实并非如此。标准用语如下

6.7.2.3标签

表格的声明

      struct-or-union identifier ;
      struct-or-union identifier
指定结构或联合类型,并将标识符声明为 该类型的标记

如果是表单的类型说明符

      struct-or-union identifier ;
      struct-or-union identifier
除作为上述其中一种形式的一部分之外发生,并且没有其他形式 将标识符声明为标记是可见的,然后声明 结构或联合类型不完整,并将标识符声明为 该类型的标记

因此,您的原始声明对具有定义良好的行为。结构的声明在定义类型别名时隐式地添加到转换单元中,然后完成。工具不允许这样做的事实可能是由于错误、工具的限制,或者可能是试图强制执行特定的编码样式


有一点支持工具可能尝试实施的样式,这与C的范围概念有关。具体来说,函数参数列表范围。作为示例,请参考此简短示例

void bar(struct foo);

struct foo {
    char c;
};

void bar(struct foo f) {}
碰巧的是,
bar
的第一个声明是使用其参数列表唯一的类型声明的。
struct foo
的初始声明与后面的函数定义中使用的类型不同。因此,守则 不会由合格的C编译器编译。在第一次函数声明之前在自己的行上声明结构可以解决此问题。

这非常清楚地表明,您可以通过一个与您的代码非常类似的示例来“前向声明”一个
typedef struct…

6.7.2.3标签
……
11以下替代配方使用typedef机制:

typedef struct tnode TNODE;
struct tnode {
    int count;
    TNODE *left, *right;
};
TNODE s, *sp; 

这是一只虫子。结构的typedef似乎与枚举的typedef被认为是相同的

对于枚举,不能在typedef定义中使用不完整的类型

来自C标准(6.7.2.3标签)

3表单的类型说明符

如果没有枚举器,则列表只能在其类型之后出现 指定已完成

例如,这样一个typedef

typedef enum E AnotherE;

enum E { N };
此typedef时无效

enum E { N };

typedef enum E AnotherE;
这是有效的

对于结构,您可以在typedef定义中使用不完整的类型

8如果是表单的类型说明符

      struct-or-union identifier ;
      struct-or-union identifier
除作为上述其中一种形式的一部分之外发生,并且没有其他形式 将标识符声明为标记是可见的,然后声明 结构或联合类型不完整,并将标识符声明为 该类型的标记


在我看来像是
iwyu
bug。C标准允许这样做。但是如果你的工具不允许,那么你需要做工具允许的事情。