Wywołanie funkcji z nieokreśloną liczbą parametrów

0

Witam,
Chce zrobić coś takiego:

void First(BYTE type,LPCSTR format,...)
{
	printf("type: %x format: %s\n",type,format);

	Second(BYTE type,LPCSTR format) // + pozostałe argumenty 
}

Używając makra va_arg można odczytać nieokreśloną liczbe parametrów, ale czy jest metoda na przekazanie nieokreślonej ilości parametrów funkcji dalej? W tym wypadku do Second?

0

Second powinna mieć w takim razie wersję przyjmującą jako drugi argument va_list - przykładowo vprintf.

0

Moja funkcja Second ma postać:
Second(BYTE type,LPCSTR format,...);
i tego nie moge zmienić. Taki format musi meć.
Czy mógłby ktoś na przykładzie pokazać jak przekazać?

0

Prawidłowo napisane metody z nieznaną liczbą argumentów i typów, powinny mieć zawsze dwie wersie jedną z "..." i jedną z va_list właśnie po to by zapobiec takim problemom. Bez tego nie masz szans.
jeśli nie możesz zmienić Second (nie masz kodu tej funkcji) ani Second nie ma wersji z va_list to stoisz na przegranej pozycji.

0

To może będzie jeszcze jakaś inna metoda na rozwiązanie problemu.
Generalnie o co chodzi?
Mam w gdzieś w pamięci funkcje Second. Ze swojego kodu ją wywołuje.

DWORD dwBack = 0xFFFFFFFF;
int __declspec(naked) Second(BYTE type,LPCSTR format,...)
{
	__asm
	{		
		jmp dwBack	// początek tej funkcji
	}		
}

Chciałbym buforować dane zanim trafią oryginalnie do Second.

Jeżeli nie ma jednolitej metody dla nieskończonej ilości argumentów to mogę zrobić wywołania ręcznie dla skończonej liczby argumentów.
To znaczy moja liczba argumentów poza type i format nieprzekroczy 6, ale uważam, że jest to naprawde niegodne programisty (za którego sie nie uważam oczywiscie) rozwiązanie.

0

Jest możliwość oszukania wywołania funkcji ze zmienną listą argumentów przez odpowiednie spreparowanie stosu przez wywołaniem. W skrócie chodzi o takie wpakowanie va_list oraz pozostałych argumentów na stos, aby ramka stosu wywołanej funkcji trafiła dokładnie w te dane. Najprościej wygenerować sobie przykładowe wywołanie z rzeczywistymi argumentami jako kod asemblerowy aby mieć przykład jak to działa i napisać funkcję opakowującą second, która będzie pobierała va_list, ładowała argumenty na stos np. przy pomocy wstawek asemblerowych (choć niekoniecznie), a następnie wywoływała samą oryginalną funkcję second przez zwykłe wywołanie z argumentami obowiązkowymi i bez argumentów dowolnych. Na przykład często jest tak, że umieszczenie na stosie argumentów wywołania nie różni się niczym od zdefiniowania zmiennych lokalnych (z inicjacją) w odpowiedniej kolejności, a następnie wywołania funkcji bez parametrów dowolnych. Być może da się nawet napisać to bez użycia jednej wstawki asemblerowej, ale trzeba to sprawdzić na wygenerowanym kodzie - czy będzie funkcjonalnie identyczny z "normalnym" wywołaniem. W końcu va_list, to zwykła tablica mapowana na stos reprezentowana faktycznie jako wskaźnik. Wystarczy podejrzeć sobie definicję va_list, va_start, va_end i odpowiednio spreparować wywołanie. Być może będzie to nawet w dużym stopniu przenośne. Oto stary przykład (z BC++ 4) zdefiniowania va_list, va_start i va_end:

#ifndef __VARARGS_H
#define __VARARGS_H

#ifdef __STDARG_H
#error Can't include both STDARG.H and VARARGS.H
#endif

#if !defined(___DEFS_H)
#include <_defs.h>
#endif

typedef void _FAR *va_list;

#define __size(x) ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int)-1))

#define va_dcl va_list va_alist;
#define va_start(ap) ap = (va_list)&va_alist
#define va_arg(ap, type) (*(type _FAR *)(((*(char _FAR * _FAR *)&(ap))+=__size(type))-(__size(type))))
#define va_end(ap)   ap = ((void _FAR *)0)

#endif  /* __VARARGS_H */

Jak widać stos z argumentami jest traktowany jak zwykła tablica. Tak więc bardzo możliwe, że trzeba mu dostarczyć na stos zwykłą tablicę zainicjowaną przez serię wywołań va_arg
Tak czy inaczej trzeba sobie podejrzeć definicje z własnego varargs.h, sprawdzić jak są odczytywane argumenty z wielokropka i odpowiednio do tego zareagować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1