-1

아래의 코드에서 첫 번째 f() 호출은 으로 전달한 -2을 대신 인쇄하는 이유는 무엇입니까?가변 함수의 정수 승격

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

void f(int64_t i, ...) 
{ 
    va_list ap; 
    int64_t j; 

    va_start(ap, i); 
    j = va_arg(ap, int64_t); 
    printf("%jd %jd\n", (intmax_t) i, (intmax_t) j); 
    va_end(ap); 
} 

int main() 
{ 
    f(-1, -2);   // Prints -1 4294967294 (bug!) 
    f(-1, (int64_t) -2); // Prints -1 -2 (fix!) 
    return 0; 
} 

왜 두 번째 f() 수정 프로그램이 작동하는지 이해할 수 있습니다. 그러나 처음 f() 호출이이 문제를 일으키는 이유를 이해할 수 없습니다. 이 행동에 대해 설명해 주시겠습니까?

답변

5

첫 번째 호출에서 인수는 int으로 전달됩니다. int이 64 비트를 사용하여 표현되지 않으면 int64_t을 추출하여 정의되지 않은 동작을 호출합니다. 프로그램의 결과로 판단하는 경우 int은 플랫폼에서 64 비트를 사용하여 표시되지 않습니다. 제 7.16.1.1/2 C11 표준 (강조 광산)에서

:

지정된 유형과 호출의 다음 인수의 값을 갖는 식에 va_arg 매크로가 확장

. 매개 변수 apva_start 또는 va_copy 매크로 (va_end의 중간 호출없이)로 초기화되어야합니다. va_arg 매크로를 호출 할 때마다 ap이 수정되어 연속 인수의 값이 순서대로 반환됩니다. 매개 변수 유형은 지정된 유형을 가진 객체에 대한 포인터의 유형이 a *를 유형 뒤에 붙임으로써 간단히 얻을 수 있도록 지정된 유형 이름이어야합니다. 실제 다음 인수가 없거나 type이 실제 다음 인수의 형식과 호환되지 않는 경우 ( 에 따라 기본 인수 판촉에 승격 됨) 다음 동작을 제외하고 동작이 정의되지 않음

- 한 유형은 부호가있는 정수 유형이고, 다른 유형은 해당 부호없는 정수 유형이며 값은 두 유형 모두에서 표시 가능합니다.

- 한 유형은 void에 대한 포인터이고 다른 유형은 문자 유형에 대한 포인터입니다.