Problem z zmienną liczbą argumentów.

0

Witam, napisałem takie coś, żeby zobaczeć czy uda mi się napisać coś co wykorzystuje stdarg.h.

void errorMessage(char* text, ...){
	string error;
	va_list arg_list;
	int iterator =0;
	va_start(arg_list, text);
	//error = va_arg(arg_list,char*);
	for(int i =0;i<iterator;i++){
		error += va_arg(arg_list, char*);
	}
	va_end(arg_list);
	
	cout << error.data() << endl;

}

No i jest tak.
Jeżeli skompilować tak jak jest to nic nie wypisze.
Jeżeli odkomentować ten komentarz i zmienić i=0 na i=1 to wywala błąd.
Przykładowo - errorMessage("test","test "," test \n Test");
Nie widzę tutaj co może być źle, więc co jest źle i jak to naprawić?

0

eee "zmienić i=0 na i=1"?
a nie przypadkiem zmienić: "int iterator =0;" na "int iterator =1;"

0

Skąd ty w ogóle bierzesz liczbę argumentów? va_arg jest prymitywne jak komentarz na onecie - po prostu idzie w górę stosu.
Musisz albo stworzyć sobie swój własny terminator (np. NULL jako ostatni argument) albo podawać ilość argumentów jako pierwszy argument.

0
pompom napisał(a)

Skąd ty w ogóle bierzesz liczbę argumentów? va_arg jest prymitywne jak komentarz na onecie - po prostu idzie w górę stosu.
Musisz albo stworzyć sobie swój własny terminator (np. NULL jako ostatni argument) albo podawać ilość argumentów jako pierwszy argument.
Lub w jakikolwiek inny sposób muisz przekazać informację o ilości argumentów w samych argumentach.

0

Gdy lista argumentów zostanie wyczerpana va_arg zwraca 0x00000001, poprawiony kod powinien wyglądać tak:

void errorMessage(char* text, ...){
	std::string error;
    va_list arg_list;
    int iterator =0;
	char *temp = (char*)0x00000001;
    va_start(arg_list, text);
    //error = va_arg(arg_list,char*);
    do{
		temp = va_arg(arg_list, char*);
		if(temp != (char*)0x00000001){
			error += temp;
		}
    }while(temp != (char*) 0x00000001);
	MessageBox(NULL,error.c_str(),"Message",MB_OK);

    va_end(arg_list);   
	//std::cout << error.data() << std::endl;
}
0
gringoM napisał(a)

Gdy lista argumentów zostanie wyczerpana va_arg zwraca 0x00000001
G. prawda

0

adf88 napisał

G. prawda

Ciekawe że to działa (kompilowałem i sprawdzałem więc wiem), no i jeszcze dodam że w MSDN jest taki przykład tego typu funkcji:

int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}

tu jest zastosowana ta sama zasada tylko że dla innego typu argumentów
</quote>

0

gringoM, że tak to ujmę: g**no prawda :]
twoja piękna funkcja z MSDN działa dobrze, jeśli się jako ostatni arg poda -1:

 // działa super
cout << average(7,1,1,-1) << endl;

 // w najlepszym wypadku wpisuje głupotę - w najgorszym mamy ostry syf
cout << average(7,1,1,10) << endl;

Cytując właśnie MSDN:

va_arg returns the current argument; va_start and va_end do not return values.

Dopisane, bo rozmowa idzie w głupią stronę:
Netaro, załóżmy sobie że funkcji np jako ostatni argument podajesz NULL, albo pusty tekst "", wtedy funkcja wygląda podobnie do twojej, ale trochę poprawiona:

#include <iostream>
#include <cstdarg>
#include <string>
using namespace std;

void errorMessage(char* text, ...){
    string error;
    va_list arg_list;
    va_start(arg_list, text);

    char* value = va_arg(arg_list, char*);
    while( value && *value ) {
        error += value;
        value = va_arg(arg_list, char*);
        }

    va_end(arg_list);
    cout << error.data() << endl;
    }

int main() {
    errorMessage("message", "first", "second", "third", "");
    errorMessage("error", "one", "two", "three", NULL);

    return 0;
    }

while(value) - dopóki wskaźnik nie jest NULLem
while(*value) - dopóki wskaźnik nie wskazuje na pusty string

0
MSDN napisał(a)
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );
0

Ranides, działa to co ty napisałeś u ciebie?
Wziąłem dokładnie kopiuj-wklej i niestety nie działa.

0

No działa, nawet przekompilowałem i uruchomiłem - mam nadzieję że nie tak starannie jak GringoM ;) Środek nocy, błędu nie widzę, rzucę okiem rano. Uściślij "nie działa" - spodziewałeś się inaczej, "połyka" pierwszy argument, program się wywala, kompilator nie chce nawet zaakceptować?

0

Temat skłonił mnie do zastanowienia się, czy nie dało by się tego rozwiązać zmiennej liczby argumantów podobnie jak jest to rozwiązane w C#.
Po kilku próbach doszedłem do wniosku, że się da :>
Oto przykład jak to zrobiłem (kompilowany pod minGW):

#include <iostream>
#include <vector>

using namespace std;

template< class T >
class MultiArg: public vector< T >
    {
public:
    MultiArg& operator,( T s )
	{
	push_back( s );
	return *this;
	}
    };

void printError( const MultiArg< const char* >& a )
    {
    if( !a.empty() )
	{
	cout << a.front();
	for( unsigned int i = 1; i < a.size(); ++i )
	    cout << '|' << a[ i ];
	}
    cout << endl;
    }

int main()
    {
    printError( (MultiArg< const char* > (), "jeden", "dwa", "trzy") );
    cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    return 0;
    }

Fakt, wada jest taka, że są podwójne nawiasy i konieczne jest jawne wpisanie zmiennej automatycznej, ale za to potem zyskuje się na kontrolowaniu typów zmiennych przez kompilator i nie ma problemu z ustaleniem ile było argumentów [soczek].
A jak jeszcze zastosować w tym szablonie typ Variant to się ma pełen wypas.

Co ciekawe, dziedzicznie (lub zamknięcie vector w klasie) jest konieczne, jak próbowałem zdefiniować po prostu operator, z vector<char*> i char* poza klasą to kompilator już tego nie puszczał.

0

Dobre ! Nigdy nie wpadłbym na przeładowanie tego operatora :D

Wpadłem jeszcze na taki pomysł:

printError << "jeden" << 2 << 3.0 << execute;

zalety:

  • mniej operatorów
  • dowolność w typach, łatwość w określeniu dozwolonych typów
  • dowolną ilość argumentów wrzucamy w dowolnym momencie
    wady:
  • odejście od koncepcji podobieństwa do wywoływania funkcji
  • konieczny terminator (nie zawsze)
0

mhm.. znany trick z operator,() :)
czesc ludzi preferuje uzywanie << albo po prostu + zamiast , wtedy mozna osiagnac takie pakowanie opcji/argumentow bez ekstra nawiasow... no ale wyglada brzydziej

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