传递“枚举"时出错在具有可变参数的函数中 [英] Error when pass "enum" in a function with variable arguments
问题描述
我正在阅读 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 enum
s. 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屋!