在C语言中,可以使用前向声明来声明枚举类型(不适用于C++)。

21
在C中,对枚举的前向声明对我来说不起作用。
我在互联网和Stack Overflow上搜索过,但是关于枚举的前向声明的问题都是关于C++的。在C中,你怎么声明枚举?
将它们放在每个文件的顶部(或者头文件中),这样文件中的所有函数都可以访问它们?

2
通常它在一个包含文件中,你能否展示一下代码以便我们看到你遇到的问题是什么? - Jesus Ramos
相关:*在C++代码中使用的C头文件中前向声明枚举* - "在C中前向声明枚举根本没有意义" - undefined
4个回答

14
将它们放在头文件中,以便所有需要它们的文件都可以访问头文件并使用其中的声明。
当使用以下选项进行编译时:
$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -c enum.c

GCC 4.2.1(在Mac OS X 10.7.1(Lion)上)接受以下代码:

enum xyz;

struct qqq { enum xyz *p; };

enum xyz { abc, def, ghi, jkl };

添加-pedantic,它会发出警告:
$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -pedantic -c enum.c
enum.c:1: warning: ISO C forbids forward references to ‘enum’ types
enum.c:5: warning: ISO C forbids forward references to ‘enum’ types

因此,在C语言中,你不应该尝试使用枚举类型的前向声明;GCC允许这种做法作为一种扩展,当不强制要求严格时。

ISO C为什么禁止对“枚举”类型进行前向引用? - pmor
因为在编译器知道定义之前,它无法确定所需存储的大小。它可能可以将值存储在1字节整数(char)中,也可能需要2或4个字节。 - Jonathan Leffler

6
你无法“前向声明”枚举类型,因为编译器不知道枚举的大小。C标准规定:“每个枚举类型都应与char、有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,但必须能够表示枚举的所有成员的值”。

难道不是因为它根本没有任何意义吗,所以才不允许这样做吗?在告诉编译器枚举名称之前,您无法引用任何枚举名称。定义没有名称的枚举有什么用处呢? - luser droog
5
你可以勉强地说一个指向不完整枚举的指针(就像我的示例代码中一样)有某种意义。但是这种意义非常微弱--你得出的结论是,在不完整的情况下它们几乎没有实际用途是正确的。 - Jonathan Leffler
6
在头文件中,您可以使用一个不完整的结构体定义,同样地,您可以有一个不完整的枚举定义,其由其他地方提供的定义支持,并且在枚举值的每个使用点都包含该定义。 - wds
@luserdroog。我的使用情况是(在头文件中): enum Foo { ... }; enum Bar; enum Foo bar2foo( Bar bar ); 因此,我们声明了一个返回Foo的函数。如果您想使用它,还需要包含Foo的定义。 - Martin Bonner supports Monica
11
这不是争论。typedef struct S S; 是有效的,但 typedef enum E E; 不行,尽管它们两者的大小都未定义。实际上,向前声明只是关于不知道相关实体的大小。 - alecov
这不仅仅是因为大小的问题,而且因为如果在指针中使用typedef,你将不知道兼容的类型和表示方式。 - Antti Haapala -- Слава Україні

0

我来到这里有同样的错误,但是这里关于代码/错误提供的信息不是太多。

我的Makefile标志为:-Wall -Wextra -Werror -pedantic -std=c17

在我的头文件中,我有以下enum

typedef enum 
{
  IS_HEAD = 1, 
  IS_VALUE = 2,
  IS_SIDE
} CoinResult;

这里的教程那里的可以参考一下:

建议使用类似于这样的代码:

enum CoinResult cr;
cr = IS_SIDE;

这导致了OP所述的错误。

通过使用以下方法解决:

CoinResult cr = IS_SIDE; 

不确定 OP 使用的是哪个 C 标准、代码或参考文献,但我有些同意:大多数针对这个相对简单问题的教程和解决方案都有点模糊。


如果变量定义和随后的赋值在文件范围内,则错误仅仅是您不能在文件范围内进行随机赋值。翻译单元由一系列“外部声明”组成,这些声明可以是函数定义或声明。赋值cr = IS_SIDE;既不是函数定义也不是声明。初始化的声明是一个声明(也是一个定义)。如果您的定义/赋值组合出现在函数作用域内,我们需要看到问题的[MCVE]。 - Jonathan Leffler

-1

CoinResult不是一个枚举,它是一种类型。如果你有

enum CoinResult {
    IS_HEAD = 1,
    IS_VALUE = 2,
    IS_SIDE,
};

那么

    enum CoinResult cr;

这是正确的。


1
这是对Qohelet答案的正确批评。但它没有直接回答原问题。 - Ross Bencina

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接