2014-07-04 3 views
2

저는 Head First C 책을 읽고 있는데 변수 인수에 대한 부분입니다. 이 코드는 컴파일하고 완벽하게 작동변수 인수가있는 함수에서 "enum"을 전달할 때 오류가 발생했습니다.

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

:

나는 다음과 같은 코드를 썼습니다.

하지만 ... 내 솔루션에는 두 가지 다른 줄이 있습니다.

내 :

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

도서 : 나는 실행 중에이 책에서 제안 된 솔루션 있지만 오류를 사용하려하고 경고보고

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

: '음료 '을 (를) 통과하면'int '로 승격됩니다.

이 책은 리눅스에서 gcc 컴파일러로 사용됩니다. Windows에서 gcc를 사용하고 있습니다.

질문 :이 책에서 제안한 코드를 컴파일 할 수없는 이유는 무엇입니까?

편집 잘못 구성되었습니다. C++ 컴파일러를 사용하여 C를 사용하려고 했었습니다. 하지만 여전히 문제가 남아 있습니다. C++에서 실행시 경고 및 오류가 발생하는 이유는 무엇입니까? 기능에

+2

내가 복제 할 수 없습니다 HTH를

enum { MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE }; 

double price(int d); 

:

일부 코딩 - 가이드 라인은 모든 곳에서 int를 사용하여, 전체 유형의 enum 사용을 피하기 만 enum 상수를 정의하는 말 너의 문제. 책 버전은 나를 위해 잘 작동합니다. gcc의 어떤 버전을 사용하고 있습니까? 'gcc --version'을 실행하십시오. – ooga

+0

컴파일러에 대한 버전 정보를 제공해주십시오. 또한 스타일과 단순성을 위해 enum 정의에 다음을 사용하십시오.'typedef enum drink { MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE } drink; 그렇게하면'enum drink '를 입력하는 대신'drink'를 유형으로 사용할 수 있습니다. – DevNull

+0

@ooga gcc (tdm-1) 4.5.2 – Macabeus

답변

4

가변 인자 인수 기본 인수 프로모션라는 변환 될 수 있습니다 : 가변 인자 함수에 전달하기 전에 int보다 작은 변환 순위와 모든 int으로 승격됩니다. 그리고 enum은 전환 순위가 더 낮습니다 (귀하의 경우에는 short 또는 기타로 표시 될 수 있음). 따라서 피 호출자가 보는 것은 int이며이를 va_arg으로 가져와야합니다.

C99 7.15.1.1 P.2 va_arg에 대한 (강조 광산) :

[...] 실제 다음 인수가없는 경우, 또는 유형이 실제 다음 인수의 형태와 호환성이없는 경우 (기본 인수 프로모션)에 따라 추진 로, 동작은 다음과 같은 경우를 제외하고 정의되지 않은 :

  • 한 종류가 다른 유형은 해당 부호없는 정수 유형 및 값이 부호있는 정수 타입이다 두 가지 유형 모두에서 표현 가능합니다.
  • [sth. 포인터 유형에 대한]

그리고 6.7.2.2, 4 페이지 :

각 열거 형은 문자, 부호있는 정수 유형 또는 부호없는 정수 유형과 호환되어야한다.유형의 선택은 구현에 따라 결정됩니다. [...]

따라서 va_arg(ap, enum drink) 버전에는 (C 표준에 관한 한) 정의 된 정의가 없습니다. 컴파일러에서 enum에 항상 int을 사용하도록 지정하지 않은 경우 최소한. 따라서 gcc에서 경고.

+0

당신의 대답은 나를 혼란스럽게합니다. "자신의 버전"에 대해 이야기 할 때, 당신은 그가'va_arg (ap, int)'를 사용하는 것을 의미합니다. 인수 승격에 의해 전달 된'enum drink '는'int'로 승격되므로이 매크로 호출은 정확할 것입니다. 책 버전에서는'va_arg (ap, enum drink)'가 사용되었고'enum drink '는'int' (실제 (승격 된) 형식의 인수)와 호환된다는 §6.7.2.2가 나와 있습니다. 그것은 정의되지 않은 행동이라고 말한다. – Anthales

+0

@Anthales : 내가 잘못 했어 ... 고마워. 고마워. 컴파일러가'enum '에'int'를 사용하지 않으면 컴파일러가 호환되지 않는다고합니다. – mafso

+0

나는 당신이 옳다고 믿습니다. enum 상수는 int 형이지만 enum 형 자체는 플랫폼에 따라 char 만 호환되므로 va_arg (ap, enum drink)는 너무 적은 바이트를 가져옵니다. 따라서 책이 잘못되어'(enum drink) va_arg (ap, int)'와 같은 것을해야합니다. – Anthales

관련 문제