C 将函数签名中的枚举声明为返回状态

C 将函数签名中的枚举声明为返回状态,c,enums,language-lawyer,return-value,C,Enums,Language Lawyer,Return Value,我最近想出了一种奇怪的方法,用c代码声明函数返回状态。执行任务的函数通常会根据成功或错误返回状态代码。这通常作为文件(或其他文件)中其他地方声明的整数或枚举发送。我发现,通过在函数签名中声明枚举,我们可以: 使可能的返回值接近函数签名 每个函数都有一组唯一的返回值,避免使用未使用的值 例如,像这样: // implementation.h enum { OK, INTERNAL_ERROR, NO_PARAMETERS } do_that(); // impleme

我最近想出了一种奇怪的方法,用c代码声明函数返回状态。执行任务的函数通常会根据成功或错误返回状态代码。这通常作为文件(或其他文件)中其他地方声明的整数或枚举发送。我发现,通过在函数签名中声明枚举,我们可以:

  • 使可能的返回值接近函数签名
  • 每个函数都有一组唯一的返回值,避免使用未使用的值
例如,像这样:

// implementation.h
enum {
    OK,
    INTERNAL_ERROR,
    NO_PARAMETERS
} do_that();

// implementation.c
enum {
    OK,
    INTERNAL_ERROR,
    NO_PARAMETERS
} do_that() {
    if (this())
        return OK;
    else if (that())
        return NO_PARAMETERS;
    return INTERNAL_ERROR;
}
我从未见过有人使用这种风格;它有效吗?若否,原因为何

我看到的一个缺点是,您必须在c文件和头文件中声明可能的返回值,但这也使您在查看签名时更容易直接使用和清楚


另一个问题是,据我所知,即使在pedantic c中也允许枚举类型之间的隐式转换,这意味着在函数声明和实现(c和h文件)中声明不同的返回状态不会生成警告或错误。

一个主要问题是,您无法使用编译器交叉检查标头和实现,因为实现TU(翻译单元)-即问题中的
implementation.c
-不能包含标头(
implementation.h
)因为枚举常量将被双重定义,这是不允许的。这意味着编译器无法发现服务提供者和使用者之间的不一致。使用者可以使用头,但提供者(
implementation.c
)不能

此外,只有一个函数可以使用
OK
(或
INTERNAL_ERROR
NO_PARAMETERS
)-其他函数的“无错误”状态需要不同的名称,每个错误状态需要不同的名称。因此,即使是小规模软件,它也不是一个实用的解决方案,即使它可以用于单个功能(但这样做不是一个好主意)


顺便说一句,请注意,尽管有
do_that()
的声明,但在头文件或实现文件中都没有它的原型。函数被声明为接受一个不确定的参数列表-已知的只是它不是形式上的可变函数(没有省略号
),它的所有参数都受规则约束(大致:
char
short
被提升为
int
float
被提升为
double
)。如果函数不带任何参数,则应将其写为
do(void)
这样在声明完成后就有一个原型可用。

这是不合法的,因为第一个枚举与第二个枚举不同,因此声明和定义具有不兼容的签名,即使它们的常量成员相同

引用第16页第6.2.5节类型

每个不同的枚举构成不同的枚举类型

尝试:

#include <stdio.h> 
// implementation.h
enum {
    OK,
    INTERNAL_ERROR,
    NO_PARAMETERS
} do_that();

// implementation.c
enum {
    OK,
    INTERNAL_ERROR,
    NO_PARAMETERS
} do_that() {
    if (mytest == 0)
        return OK;
    else if (mytest == 1)
        return NO_PARAMETERS;
    return INTERNAL_ERROR;
}

int main() 
{ 
    printf("do_that(%d) = %d\n",0,do_that(0));
    printf("do_that(%d) = %d\n",1,do_that(1));
    printf("do_that(%d) = %d\n",2,do_that(2));
    return 0; 
} 
所以你不能:

  • 将您的.h包含在.c中

  • 声明函数原型


为什么不使用typedef?

为什么不使用typedef?你用哪种编译器编译这段代码?因为重新定义而不高兴…即使枚举数值相同,我也不相信这是合法的C。如果枚举数值在任何方面都不同,那么这肯定不是使该技术无用的原因。尽管如此,这是正确的如果这些值与您提供的值相同,这是一个有趣的问题。@Closer:这是如何基于意见的?每个文件都是独立有效和可用的。您不能做的是在
implementation.c
中包含
implementation.h
——这意味着您丢失了头通常提供的交叉检查。这是第谢谢。这适用于单个TU。TUs中存在不同的问题。有关TUs之间共享定义的一些规则,请参阅。这将如何使它们不兼容?6.2.7§1说明类型是兼容的。"此外,如果在单独的翻译单元中声明的两个结构、联合或枚举类型的标记和成员满足以下要求,则它们是兼容的:如果一个使用标记声明,另一个应使用相同的标记声明。如果这两个类型都在各自的翻译单元中的任何位置完成,则以下附加要求适用:其成员之间应存在一对一的对应关系,以便每对对应成员都使用兼容类型声明;“/--/”对于两个枚举,对应成员应具有相同的值
Main.c:11:5: error: redefinition of enumerator 'OK'
    OK,
    ^
Main.c:4:5: note: previous definition is here
    OK,