Reputation: 4572
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?
Upvotes: 2
Views: 5927
Reputation: 5543
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
Upvotes: 7