2010-02-05 6 views
6

이것은 이상한 질문이지만 다른 기능으로 전달하기 전에 va_list의 내용을 조작하는 표준 방법이 있습니까? 내가, 내가 이제 결과 (10)를 얻을 수의 대신 직접 vsum를 호출, sum 중간 함수를 호출한다고 가정 할 것으로 예상 sumsum(4, 1, 2, 3, 4)로 호출하는 경우가변 인수를 조작하는 표준 방법은 무엇입니까?

int vsum(int n, va_list ap) { 
    int total = 0; 
    for (int i = 0; i < n; ++i) { 
     total += va_arg(n, int); 
    return total; 
} 

int sum(int n, ...) { 
    va_list ap; 
    va_start(ap, n); 
    int total = vsum(n, ap); 
    va_end(ap); 
    return total; 
} 

: 예를 들어, 나는 두 가지 기능 sumvsum이 있다고 가정 , vsum_stub 다음을 수행한다 : 나는 sum(4, 1, 2, 3, 4)를 호출 할 때

int vsum_stub(int n, va_list ap) { 
    va_list temp_ap; 
    va_copy(temp_ap, ap); 
    for (int i = 0; i < n; ++i) { 
     int *arg = &va_arg(ap, int); 
     *arg += 2; 
    } 
    va_end(temp_ap); 
    return vsum(n, ap); 
} 

지금, 나는에서 vsum_stub 단위로 모든 값 때문에, 결과 (20)를 다시 얻어야한다210 by 2. 이것은 va_arg의 결과 주소를 취할 수 없기 때문에 물론 컴파일되지 않습니다. 그래도 이렇게 할 수있는 또 다른 방법이 있습니까? 나는 C99에서 일하고있다.


배경 : 나는 데이터를보다 효율적인 형식으로 힙에 저장 될 수 있도록 몇 가지 포인터 변환을 수행하는 라이브러리에서 일하고 있어요

. 프로그램은 호출을 printf과 같은 라이브러리 함수로 변환하여 내 스텁 함수 (예 : hc_printf)로 변환하는 사용자 정의 변환으로 컴파일됩니다. hc_printf은 실제 printf 함수에 인수를 전달하기 전에 포인터 인수 (%s 용 문자열)를 변환해야합니다.

편집 : 다음은 코드 예제입니다. 문자열이 foo이라고 가정 해 봅시다. foo은 가짜 포인터를 반환하는 malloc의 수정 된 버전으로 동적으로 할당됩니다. 컴파일러는 가짜 포인터를 처리 할 수 ​​있도록 프로그램을 수정합니다. 그래서이 작품 : 나는 (의사의)이 같은 fake_vprintf 함수를 작성 할

char *foo = fake_malloc(4); 
fake_strcpy(foo, "foo"); 

:

int fake_vprintf(const char *format, va_list args) { 
    for each pointer argument p in args 
     translate p to q, a real pointer to contiguous memory 
     replace p with q in args 
    } 
    return vprintf(format, args); 
} 

프로그램은 가짜 포인터를 사용하여 단지 원래 vprintf처럼 fake_vprintf을 부를 것이다. fake_vprintf은 가짜 포인터를 실제 vprintf이 사용할 수있는 실제 포인터로 변환합니다.

+0

'int * arg = va_arg (ap, int *);'가 아닌'int * arg = & va_arg (ap, int) – dirkgently

+0

@dirkgently, 아니요, 인수 목록의 실제 매개 변수는 int입니다. 그 예제에서 내 의도는 그 값을 바꿀 수 있도록리스트 안에 그 int에 대한 포인터를 얻는 것이었다. –

+0

'vsum_stub'는'int *'의리스트를 취한다고 가정했습니다. 어쨌든 제가 게시 한 코드가 도움이된다고 생각합니까? – dirkgently

답변

2

아하, 내가 알기로 귀하의 문제는 표준 vprintf 기능을 전달하기 위해 새로운 va_list 인수를 생성하고 있습니다. 차례 차례로, 당신은리스트의 각 멤버를 수정하도록 요구할 것입니다. 그러나 이러한 목록에 대해 요소 현명한 가져 오기/편집/삽입 작업이 없으므로 사용자가 고생하게됩니다.

나는 이것을하는 어떤 방법을 정말로 보지 못합니다. 물론 vprintfin situ 변형을 적용 할 수 있습니다. 한 번에 하나의 인수가 사용됩니다. 제 제안은 다음과 같습니다. 을 모두 다시 작성하십시오. 표준 라이브러리 함수 - 여하튼 래퍼를 작성하고 있습니다. 이것은 약간의 작업을 필요로하지만, 이미 hc_printf 등으로 일부분을 수행하고 있으므로, 전체 거리로 이동하지 마십시오 (함수 호출에서 어떤 것이 저장되는지 추측 해보십시오!).

+0

vprintf와 친구들을 다시 구현하는 것이 가장 정확한 해결책 일 것입니다. va_arg를 사용하여 va_list의 값을 수정할 수있는 방법이 있었으면 합니다만, 그런 일은 불가능합니다. vprintf와 친구들을 재 구현하는 것이 더 나은지 또는 각 플랫폼에 대해 플랫폼 별 솔루션을 갖는 것이 더 좋은지를 결정해야 할 것입니다. –

3

아마도 플랫폼에 구애받지 않는 방식으로 va_list를 사용할 수 없습니다.자신의 환경이 stdarg.h에있는 va_list를 정의하는 방법을 살펴보고 작업 할 수있는 도구를 작성해야합니다.

예를 들어, va_list가 (char *) 일 경우, 모든 종류의 작업을 수행 할 수 있습니다.

// add 1000 to the integer stored on the stack and advance va_list 
*(int *)va_list += 1000; 
va_list += sizeof(int); 

당신은 (= 1000 +) 당신이 그것을합니다 (INT * 캐스트를 통해)를 int에 대한 포인터를의 va_list 고려할 컴파일러, 값 (*)를 가지고 있으며 1000을 추가 말하는 거 . 이제 va_list 포인터를 스택의 다음 인수로 넘깁니다.

+0

이것은 내가 현재 사용하고있는 것입니다. 그래서 +1합니다. Linux에서 x86-32에서 작동합니다. 그러나 결국에는이 코드를 ARM 및 x86-64로 이식해야하며이 두 아키텍처가 모두 레지스터에 인수를 전달하므로이 방법이 훨씬 복잡해 질 수 있습니다. –

관련 문제