在带有可变参数的函数中传递“枚举”时出错

Mac*_*eus 2 c arguments

我正在阅读《 Head First C》一书,是有关可变参数的部分。

我写了以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

enum drink {
    MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE
};

double price(enum drink d) {
    switch(d) {
    case MUDSLIDE:
        return 6.79;
    case FUZZY_NAVEL:
        return 5.31;
    case MONKEY_GLAND:
        return 4.82;
    case ZOMBIE:
        return 5.89;
    }
    return 0;
}

double calc(int args, ...) {
    double total = 0;

    va_list ap;
    va_start(ap, args);

    int i;
    for (i = 0; i < args; i++) {
        int currentDrink = va_arg(ap, int);
        total += price((drink) currentDrink);
    }

    va_end(ap);
    return total;
}

int main() {
    printf("Price is %.2f\n", calc(2, MONKEY_GLAND, MUDSLIDE));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该代码可以编译并完美运行。

但是...我的解决方案有两行。

我的:

int currentDrink = va_arg(ap, int);
total += price((drink) currentDrink);
Run Code Online (Sandbox Code Playgroud)

书:

enum drink currentDrink = va_arg(ap, enum drink);
total += price(currentDrink);
Run Code Online (Sandbox Code Playgroud)

我尝试使用本书中提出的解决方案,但执行过程中出错并报告警告:通过“ ...”传递时,“ drink”会提升为“ int”

本书用于Linux上的gcc编译器。我在Windows上使用gcc。

问题:我无法编译本书中提出的代码的原因是什么?

编辑 那里配置错误。使用C ++编译器正在考虑使用C。但是问题仍然存在:为什么在C ++中导致执行过程中出现警告和错误?

maf*_*fso 5

函数的可变参数要进行称为默认参数提升的转换:转换等级小于传递给可变函数之前int提升为的所有东西int。并且enum转换等级较小(short在您的情况下,可以用或表示)。因此,您的被呼叫者看到的是一个int,必须这样来获取它va_arg

C99 7.15.1.1 p.2(强调我的)关于va_arg

[…]如果没有实际的下一个自变量,或者类型与实际的下一个自变量的类型不兼容(根据默认参数Promotions的提升),则该行为是不确定的,除了以下情况:

  • 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且值在两种类型中均可表示;
  • [某事。关于指针类型]

6.7.2.2,第4页:

每个枚举类型应与char,有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,[…]

因此,该va_arg(ap, enum drink)版本没有定义的行为(就C标准而言)。至少,如果编译器未指定始终int用于enums。因此来自的警告gcc

一些编码准则说,要避免enum完全使用类型,而要int在各处使用并且仅定义enum常量:

enum {
    MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE
};
Run Code Online (Sandbox Code Playgroud)

double price(int d);
Run Code Online (Sandbox Code Playgroud)

高温超导

  • @KeplerBR这基本上是您的答案:本书的版本没有明确定义的C(它是与平台相关的;仅当您的枚举类型是用`int`类型实现时才正确);它也不是定义明确的C ++(C ++ Working Draft N3242,§7.2p.6与§6.7.2.2p.4基本相同)。我猜想C ++编译器发出警告而不C编译器发出警告的原因仅仅是因为C编译器在历史上远没有那么复杂-因为那样,它可以更容易维护。这样的警告可以看作是混乱的,并且有特定的代码分析程序,因此“它不是真正需要的”。 (2认同)
  • @KeplerBR枚举类型的问题在于它们的基本类型没有明确定义。它可以是“ char”,“ short”,“ unsigned short”等。在某些情况下,更确切地说,在类型大小很重要的情况下,使用枚举类型可能很麻烦。基本上所有使用sizeof x的东西(其中x是/具有枚举类型)都可能是错误。va_args是使用sizeof的宏的一个示例,由于枚举类型的模糊性而中断了。就个人而言,我不会阻止枚举类型的使用,只要它能增加可读性即可(但还有“ typedef”)。 (2认同)