2016-10-29 13 views
1

variadic 함수는 숫자 상수를 정확히 어떻게 처리합니까? 예 :Variadic 함수 및 상수

myfunc(5, 0, 1, 2, 3, 4); 

기능은 다음과 같습니다 : 다음 코드를 고려 va_arg로 단일 인수를 반복하기 위해,

void myfunc(int count, ...) 
{ 
} 

자, 예를 들어, 자신의 크기를 알 필요가 int, short, char, float 등입니다. 그러나 위의 코드에서 사용한 것과 같은 수치 상수로 가정해야하는 크기는 무엇입니까?

시험은 단지 그들을 위해 int 가정하면 컴파일러는 이러한 상수는 또한 단일 char 또는 short 각으로 표현 될 수있다하더라도 int로 밀어 보인다 있도록 잘 작동하는 것 같다 것으로 나타났습니다.

그럼에도 불구하고 나는 내가 보는 행동에 대한 설명을 찾고 있습니다. variadic 함수에 숫자 상수를 전달하기위한 C의 표준 유형은 무엇입니까? 이것은 명확하게 정의 되었습니까, 아니면 컴파일러에 종속적입니까? 32 비트와 64 비트 아키텍처간에 차이점이 있습니까?

감사합니다.

답변

3

나는 Jonathan Leffler's answer을 좋아하지만, 휴대용 라이브러리 또는 가변 API를 제공하는 사람을 위해 기술적 인 세부 사항을 다룰 줄 알았습니다. 따라서 세부 사항을 조사해야합니다.

가변 인자 파라미터 default argument promotions 대상이다 (C11 초안 N1570 PDF로서 섹션 6.5.2.2 함수 호출, 제 6 항)

..정수 승격은 각 인수에 대해 수행되고 유형 float 인수는 double으로 승격됩니다. 이를 기본 인수 프로모션라고합니다.

.. 홍보 후 인수의 유형 승진 후 매개 변수들과 호환되지 않는, 행동이 다음과 같은 경우를 제외하고 정의되지 않은 [경우] :

  • 한 승진 유형 인 부호있는 정수 유형이고 다른 승격 된 유형은 해당 부호없는 정수 유형이며이 값은 두 유형 모두에서 나타낼 수 있습니다.

  • 두 가지 유형은 1.0f 같이 f 또는 F (접미사로하지 않는

부동 소수점 상수를 입력 double의있는 문자 유형의하거나 규정 버전 또는 무효

에 대한 포인터)이 경우 유형은 float입니다.

C99 및 C11에서 정수 상수는 int이고 하나가 맞으면; long (AKA long int). 그렇지 않으면 long long (AKA long long int)입니다. 많은 컴파일러가 크기 접미사가없는 정수 상수는 사람의 실수 또는 오타라고 가정하므로 정수 상수가 int이 아닌 경우 항상 접미사를 포함하는 것이 좋습니다. long int

  • lu 또는 ul 또는 LU 나에 대한 unsigned int

  • l 또는 L에 대한

    • u 또는 U :

      정수 상수는 자신의 유형을 표시하기 위해 편지 접미사를 가질 수 있습니다 UL 또는 unsigned long long int

    에 대한 long long int

  • llu 또는 LLU (또는 ULL 또는 대문자 또는 소문자 변형의)에 대한 unsigned long int

  • ll 또는 LL 또는 Ll 또는 lL에 대한 lU 또는 Lu 또는 uL 또는 Ul

    integer promotion 규칙은 6.3.1.1 절에 있습니다.

    • floatdouble

    • 모든 정수 타입으로 승격됩니다

      는 (C89 및 C99에 비해 몇 가지 추가,하지만 큰 변화가) C11의 기본 인수 추진 규칙을 요약하면 int으로 표시 될 수있는 값은 int으로 승격됩니다. (이 부호 및 charshort 및 유형 _Bool, int 비트 필드, 작은 unsigned int 비트 필드 서명 모두 포함한다.)

    • 그 값 unsigned int로 표현 될 수있다 (뿐만 아니라 int 모든 정수형)는 unsigned int으로 승격됩니다. (이 unsigned int 비트 환언에서, int (CHAR_BIT * sizeof (unsigned int)의 비트로 표현 될 수없는 필드) 및 unsigned int의 typedef되어 별칭을 포함하지만 제 생각예요.)

    • 정수형 적어도 큰 int은 변경되지 않습니다. 여기에는 long/long int, long long/long long intsize_t 등의 유형이 포함됩니다. "서명에 서명 불확실입니다 서명에 서명, 괜찮습니다":

    내가 지적하고자하는 규칙에 하나 '의 잡았다'이

    • 경우] 인수가 부호있는 정수 유형으로 승격되었지만 함수가 해당 부호없는 정수 유형을 사용하여 값을 얻으면 함수는 모듈로 산술을 사용하여 올바른 값을 얻습니다.

      즉, 음수 값은 (부호없는 정수 유형에서 1 + 최대 표현 가능 값)만큼 증가하여 긍정적 인 값을 갖게됩니다.

    • 인수가 부호없는 정수 유형으로 승격되었지만 함수가 해당 부호가있는 정수 유형을 사용하여 값을 얻고 그 값이 둘 다에서 표현 가능하면 함수는 올바른 값을 얻습니다. 값이 양쪽 모두에서 표현할 수없는 경우, 동작은 구현에 의해 정의됩니다. 실제적으로, 거의 모든 아키텍쳐는 상기와 반대가된다. 즉, 얻어진 부호있는 정수 값은 (1 + 부호없는 정수 유형의 가장 큰 표현 가능한 값)에 의해 깎인 부호없는 값과 일치한다. 어떤 이상한 것들은 정수 오버플로 또는 비슷한 이상한 신호를 보낼 수 있다고 들었지만 그런 기계에서는 결코 내 핏줄을 얻지 못했습니다. 당신이 지정자를 printf와 위의 규칙을 비교한다면

    man 3 printf 사람 페이지 (리눅스 맨 페이지 프로젝트의 의례), 매우 유익한 것입니다. 마지막에 make_message() 예제 함수 (vsnprintf()에 필요한 C99, C11 또는 POSIX)도 재미 있어야합니다.

  • +0

    답변 해 주셔서 감사합니다. ! 나는 여기에 후속 조치를했다 : http : // stackoverflow.com/questions/40330749/why-does-my-variadic-function-work-both-int-and-long-long – Andreas

    1

    1을 쓸 때, 이는 int 상수입니다. 컴파일러가 사용할 수있는 다른 유형은 없습니다. 다른 유형을 요구하는 함수에 대해 가변적이지 않은 프로토 타입이있는 경우 컴파일러는 정수 1을 적절한 유형으로 변환하지만 1int 상수입니다. 따라서 귀하의 예에서 6 개의 모든 인수는 int입니다.

    호출 된 가변 함수가 처리하기 전에 어떻게 든 인수의 유형을 알아야합니다. printf() 계열의 함수를 사용하면 형식 문자열을 통해 예상되는 내용을 알 수 있습니다. 함수의 scanf() 패밀리와 비슷합니다.

    기본 변환은 가변 인수 함수의 줄임표에 해당하는 인수에 적용됩니다. 예를 들어, 주어진 :

    char c = '\007'; 
    short s = 0xB0hD; 
    float f = 3.1415927; 
    

    전화로 : 사용

    int variadic_function(const char *, ...); 
    

    :

    int rc = variadic_function("c s f", c, s, f); 
    

    실제로 모두 cintsdouble-f 변환합니다.

    +0

    답변 해 주셔서 감사합니다. 여기에 후속 조치가 있습니다. http://stackoverflow.com/questions/40330749/why-does-my-variadic-function-work-with-both-int-and-long-long – Andreas

    관련 문제