【问题标题】:Declaring enum in function signature as return status将函数签名中的枚举声明为返回状态
【发布时间】:2019-04-09 06:43:45
【问题描述】:

我最近想出了一种我认为在 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 文件和头文件中声明可能的返回值,但这也使得它在您查看签名时更加可用和直接清晰。

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

【问题讨论】:

  • 为什么不用 typedef?
  • 你用哪个编译器编译这段代码? gcc 不高兴因为重新定义...
  • 即使枚举器值相同,我也不相信这是合法的 C。如果枚举器值有任何不同,那么肯定不是这使得该技术无用。尽管如此,如果这些值与您提供的值相同,这是一个有趣的问题。
  • @Closers:这个观点是如何建立的?
  • 每个文件都是独立有效和可用的。你不能做的是在implementation.c 中包含implementation.h——这意味着你失去了标题通常提供的交叉检查。

标签: c enums language-lawyer return-value


【解决方案1】:

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

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

顺便提一下,尽管有do_that() 的声明,但在头文件或实现文件中都没有它的原型。该函数被声明为采用不确定的参数列表——我们所知道的是它不是正式的可变参数函数(没有省略号...),它的所有参数都受default argument promotion 规则的约束(大致为:@987654330 @ 和short 提升为intfloat 提升为double)。如果函数不带参数,则应将其写为do_that(void),以便在声明完成后有可用的原型。

【讨论】:

    【解决方案2】:

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

    引自 6.2.5 类型 p。 16

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

    【讨论】:

    • 就是这个。谢谢。
    • 这适用于单个 TU。 TU 之间存在不同的问题。有关 TU 之间共享定义的一些规则,请参阅 §6.2.7 Compatible type and composite type
    • 这会让它们不兼容吗? 6.2.7 §1 说类型是兼容的。
    • "此外,在单独的翻译单元中声明的两种结构、联合或枚举类型,如果它们的标签和成员满足以下要求,则它们是兼容的:如果一个用标签声明,另一个应该用相同的标签。如果两者都在各自翻译单元内的任何地方完成,则适用以下附加要求:它们的成员之间应存在一一对应关系,以便每对对应的成员都声明为兼容的类型;" /--/ "对于两个枚举,对应的成员应该具有相同的值。"
    【解决方案3】:

    尝试:

    #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; 
    } 
    

    给予:

    Main.c:11:5: error: redefinition of enumerator 'OK'
        OK,
        ^
    Main.c:4:5: note: previous definition is here
        OK,
    

    所以你不能:

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

    • 声明函数原型

    为什么不直接使用 typedef?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 2013-08-15
      • 2012-08-20
      相关资源
      最近更新 更多