2016-11-03 7 views
3

다음 프로그램은 64 비트 Linux 컴퓨터에서 작동하지만 32 비트 Linux 컴퓨터에서 충돌합니다.조각으로 va_list 처리

#include <cstdarg> 
#include <iostream> 

void proc_int(std::va_list va) 
{ 
    std::cout << va_arg(va, int); 
} 

void proc_str(std::va_list va) 
{ 
    std::cout << va_arg(va, const char*); 
} 

void outputv(std::va_list va) 
{ 
    proc_int(va); 
    std::cout << " "; 
    proc_str(va); 
    std::cout << "\n"; 
} 

void output(int dummy, ...) 
{ 
    va_list va; 
    va_start(va, dummy); 
    outputv(va); 
    va_end(va); 
} 

int main() 
{ 
    output(0, 42, "hello"); 
} 

나는 va_list 32 비트에 char*하지만 struct __va_list_tag[1] 64 비트에 있기 때문에 이것은 믿습니다. 이 프로그램을 휴대 가능하게 만들려면 어떤 변경을해야합니까? outputv의 서명을 변경하지 않는 것이 좋습니다. cppreference에서

+1

포인터로 전달 : http://ideone.com/bhKalu –

+0

@ n.m. 64 비트에서 오류 : '__va_list_tag **'를 __va_list_tag (*) [1]로 변환 할 수 없습니다. – aschepler

답변

1

이의 va_list 배열 여부로 typedefed 여부를 작동합니다 :

#include <cstdarg> 
#include <iostream> 
#include <type_traits> 

using my_va_list = std::decay<std::va_list>::type; 

void proc_int(my_va_list &va) 
{ 
    std::cout << va_arg(va, int); 
} 

void proc_str(my_va_list &va) 
{ 
    std::cout << va_arg(va, const char*); 
} 

void outputv(std::va_list va) 
{ 
    my_va_list mva = va; 
    proc_int(mva); 
    std::cout << " "; 
    proc_str(mva); 
    std::cout << "\n"; 
} 

적어도 모든 gcc, clang 및 vC++에서는 작동하지 않을 수 있지만 모든 32 비트 및 64 비트 모드에서 작동합니다. C 표준에 따르면

3

, 그것은 그 (이후 사용가) 다른 함수에 전달 포함되어 있지만 확실히 그럴듯 여부 전적으로 분명하지 않다

If a va_list instance is created, passed to another function, and used via va_arg in that function, then any subsequent use in the calling function should be preceded by a call to va_end

.

비교를 위해 로컬 (리눅스) 매뉴얼 페이지를 확인 :

If ap[the va_list] is passed to a function that uses va_arg(ap,type) then the value of ap is undefined after the return of that function

그래서 당신은 단순히 주변의 va_list를 통과하고 그것에게 당신이 방법을 사용할 수 없습니다 것

, 그냥가 발생하는 32 비트 버전을 을 가지고 도망 치다.

What changes can I make to make this program portable, preferably without changing the signature of outputv?

음, 단지 다른 기능으로 va_list를 통과하고 아직도 이후에 일을 기대하지 않는다 :

void outputv(std::va_list va) 
{ 
    std::cout << va_arg(va, int); 
    std::cout << " "; 
    std::cout << va_arg(va, const char *); 
    std::cout << "\n"; 
} 
+0

어. 나는'va_list &'를 많이 통과시키는 레거시 코드를 가지고있다. 그러나 'va_list'는 포인터로 변환 된 배열 인 경우 va_list 매개 변수에 바인드 할 수 없습니다. – aschepler

+1

대부분의 경우 파손은 32 비트에서 호출 규칙이 변경 되었기 때문일 수 있지만 해결할 수는 없습니다. 'va_list '를 사용하지 않고 실제로하고있는 것을 구현하는 방법에 대해 질문 할 수 있습니다. – Useless

0

(그 가변 인자 기능을 직접 C++로 포함되어 있음), C99, 7.15 제 3 항 (강조 광산)

The type declared is va_list which is an object type suitable for holding information needed by the macros va_start , va_arg , va_end , and va_copy . If access to the varying arguments is desired, the called function shall declare an object (generally referred to as ap in this subclause) having type va_list . The object ap may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap , the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap .212)

하면 함수에 va_list 전달되고 그 때문에 그 안에 va_arg을 사용하면 해당 함수가 반환 된 후 해당 va_list을 다시 사용할 수 없습니다. 그리고 "212"노트는 해결책을 제시합니다 :

212) It is permitted to create a pointer to a va_list and pass that pointer to another function, in which case the original function may make further use of the original list after the other function returns.