传递“枚举"时出错在具有可变参数的函数中 [英] Error when pass "enum" in a function with variable arguments

查看:23
本文介绍了传递“枚举"时出错在具有可变参数的函数中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 Head First C 一书,我是关于变量参数的部分.

我写了以下代码:

#include #include #include 枚举饮料{泥石流、FUZZY_NAVEL、MONKEY_GLAND、ZOMBIE};双倍价格(枚举饮料d){开关(d){案例泥石流:返回 6.79;案例 FUZZY_NAVEL:返回 5.31;案例 MONKEY_GLAND:返回 4.82;案例僵尸:返回 5.89;}返回0;}双计算(int args,...){双倍总数 = 0;va_list ap;va_start(ap, args);国际我;for (i = 0; i < args; i++) {int currentDrink = va_arg(ap, int);总计 += 价格((饮料)currentDrink);}va_end(ap);总回报;}int main() {printf("价格是 %.2f\n", calc(2, MONKEY_GLAND, MUDSLIDE));返回0;}

代码编译并完美运行.

但是......我的解决方案有两行不同的内容.

我的:

int currentDrink = va_arg(ap, int);总计 += 价格((饮料)currentDrink);

图书:

enum Drink currentDrink = va_arg(ap, enum Drink);总计 += 价格(当前饮料);

我尝试使用书中提出的解决方案,但是在执行过程中报错并报了一个警告:'drink'通过'...'被提升为'int'>

本书是在linux上使用gcc编译的.我在 Windows 上使用 gcc.

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

编辑还有配置错误.正在使用 C++ 编译器正在考虑使用 C.但问题仍然存在:为什么在 C++ 中会导致执行中出现警告和错误?

解决方案

函数的可变参数受到称为默认参数提升的转换:所有转换等级小于 的转换int 在传递给可变参数函数之前被提升为 int.并且 enum 具有较小的转换等级(并且在您的情况下可能表示为 short 或其他内容).所以你的被调用者看到的是一个 int 并且必须通过 va_arg 获取它.

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

<块引用>

[…] 如果没有实际的下一个参数,或者类型与实际的下一个参数的类型不兼容(根据默认参数提升),则行为未定义, 以下情况除外:

  • 一种是有符号整数类型,另一种是对应的无符号整数类型,值在两种类型中都可以表示;
  • [某事.关于指针类型]

和 6.7.2.2,第 4 页:

<块引用>

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

因此,va_arg(ap, enum Drink) 版本没有定义的行为(就 C 标准而言).至少,如果编译器没有指定总是对 enum 使用 int.因此来自 gcc 的警告.

一些编码指南说要完全避免在类型中使用 enum,在任何地方都使用 int 并且只定义 enum 常量:

enum {泥石流、FUZZY_NAVEL、MONKEY_GLAND、ZOMBIE};

双倍价格(int d);

HTH

I'm reading the book Head First C and I am the part about the variable arguments.

I wrote the following code:

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

The code compiles and works perfectly.

But... There are two different lines of my solution with the book.

My:

int currentDrink = va_arg(ap, int);
total += price((drink) currentDrink);

Book:

enum drink currentDrink = va_arg(ap, enum drink);
total += price(currentDrink);

I tried to use the solution proposed in the book, but the error during execution and reports a warning: 'drink' is promoted to 'int' when passed through '...'

The book is used gcc compiler on linux. I am using gcc on Windows.

Question: What is the reason I was unable to compile the code proposed in the book?

Edit There configured wrong. Was using a C++ compiler was thinking of using a C. But the question remains: why in C++ results in a warning and error in the execution?

解决方案

Variadic arguments to functions are subject to a conversion called default argument promotions: Everything with a conversion rank smaller than that of int gets promoted to int before passed to a variadic function. And an enum has a smaller conversion rank (and may be represented as a short or something else in your case). So what your callee sees is an int and must fetch it by va_arg as such.

C99 7.15.1.1 p.2 (emphasis mine) about va_arg:

[…] If there is no actual next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:

  • one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;
  • [sth. about pointer types]

And 6.7.2.2, p.4:

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, […]

So, the va_arg(ap, enum drink) version has no defined bahavior (as far as the C standard is concerned). At least, if the compiler doesn't specify to always use int for enums. Hence the warning from gcc.

Some coding-guidelines say to avoid enum usage for types entirely, using int everywhere and only define enum constants:

enum {
    MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE
};

and

double price(int d);

HTH

这篇关于传递“枚举"时出错在具有可变参数的函数中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆