Kalender 
Kalender TerminKalender
Mi 24.12.2025
Do 25.12.2025
Fr 26.12.2025
Sa 27.12.2025
So 28.12.2025
Mo 29.12.2025
Di 30.12.2025

Werbe Banner:
.

C++ Weihnachtsgeschenk - variadic functions
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    -=]Die with Honor[=- Foren-Übersicht » Hard & Softwareecke
Autor Nachricht
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 24.11.2005, 23:56    Titel: C++ Weihnachtsgeschenk - variadic functions
24.11.2005
Benutzer-Profile anzeigen 

Für alle die es interessiert, speziell für die Leute die mit C++ arbeiten hab
ich ein nettes kleines Geschenk. Ich hab heute ne spezielle Klasse für
Errorhandling geschrieben und bin dabei auf einen eher unbekannten C++
Trick gestossen. Wer sich immer mal gefragt hat wie man Funktionen er-
stellt die eine beliebige Anzahl an Argumenten akzeptiert und diese auch
verarbeitet, wird sicherlich gefallen daran finden.

Ich hab also angefangen eine Fehlerbehandlungsklasse zu erstellen. Meine
Klasse stellt 3 Funktionen zur Fehlerbehandlung zur Verfügung. Die erste
schreibt die jeweilige Fehlermeldung in eine Datei error.log, die zweite gibt
die jeweilige Fehlermeldung in einer Message Box aus, und die dritte ist
für kritische Fehler gedacht, diese sendet eine Warnung an den User per
Message Box, schreibt die jeweilige Fehlermeldung in die Datei error.log
und beendet die Anwendung.
Das ist generell sehr simpel, allerdings wollte ich mich damit nicht zufrieden
geben. Zur besseren Fehleranalyse sollte es möglich sein, mit der Fehler-
meldung auch Zahlen zu übergeben, in der Art von printf(). Also zum
Beispiel:
Code:
printf("Diese Zahl: %d wird von printf in den String kopiert.",10);

Die Ausgabe in der Datei sieht dann so aus:
Diese Zahl: 10 wird von printf in den String kopiert.

Das funktioniert mit beliebig vielen Zahlen, und auch anderen Variablen-
typen. Für die Fehlerbehandlung sind Zahlen jedoch genug. Dann kam das
eigentliche Problem auf. Ich hatte keine Ahnung wie so etwas funktioniert.
Bis dato wusste ich nicht wie sich solche Funktionen nennen, also war es
relativ schwierig darüber etwas zu finden. Nach Stundenlanger Kleinarbeit
hatte ich dann endlich verschiedene Quellen bei Google gefunden, musste
aber leider feststellen, das die meissten Fehlerhaft oder nur sehr dürftig
waren. Schlussendlich hab ich aber herausgefunden wie es funktioniert, teils
durch Google, teils einfach durch ausprobieren.

Funktionen die eine unbestimmte Anzahl an Argumenten akzeptieren nennt
man "variadic functions". Diese werden folgendermassen definiert:
Code:
 Rückgabewert Funktion(Argument1, Argument2, ...);
// Beispiel:
void PrintToFile(char *cText, ...);

Damit kann man jetzt so viele Parameter übergeben wie man will. Allerdings
werden diese von der Funktion, bis auf den ersten völlig ignoriert.
Unbekannte Parameter sind immer vom Typ void*, Leerzeiger also. Im
Standardheader <cstdarg.h> werden macros zur Behandlung der unbekannten
Parameter definiert. Wir werden die Macros va_start, va_arg und va_end
benutzen. Dazu brauchen wir noch einen Zeiger vom Typ va_list (dieser ist
nichts anderes als ein Zeiger vom Typ void*), um die Parameter zu ver-
wenden. Dann kommt der etwas kompliziertere Teil. Bildlich muss man sich
das so vorstellen:

Funktionsabbild im Speicher
{Funktionsadresse} {Adresse-Parameter1} {Adresse-aller-unbekannten}

Bekannte Paramater und die Funktion selbst haben eine bestimmte Grösse
im Speicher, diese müssen uns nicht interessieren. Der wichtige Punkt sind
die unbekannten, von der wir nur die Startadresse kennen. Alle die Para-
meter die nicht bekannt sind, werden aneinandergehängt und als ein Block
behandelt, wie wenn es nur ein Parameter wäre. Was wir also tun müssen,
ist unserem void* Zeiger die Startadresse des Parameterblocks zuzuweisen.
Dies geschieht folgendermassen:
Code:
va_list vl; // könnte auch void* vl; sein
va_start(vl,cText);

va_start setzt jetzt also unseren Leerzeiger auf die Startadresse des Para-
meterblocks den wir nicht kennen. Irgendwie müssen wir jedoch wissen was
wir mit diesem Block an Argumenten anfängen sollen, dazu kommt cText
ins Spiel. Wir benutzen #d um Zahlen in unseren Text einzufügen. Was
unsere Funktion nun tun muss, ist einfach durch cText zu schauen bis ein
#d vorkommt. Dieses #d muss er dann durch die erste Zahl auf die vl zeigt
ersetzen, und vl um die Anzahl bytes dieser Zahl erhöhen, so das vl auf
die erste Adresse hinter dieser Zahl zeigt. Das kann manuel gemacht
werden, aber wir wollen ja nicht das Rad zweimal erfinden, also benutzen wir
das Makro va_arg(). Wenn wir jetzt also in cText auf ein #d stossen, rufen
wir va_arg folgendermassen auf:
Code:
int nNummer = va_arg(vl,int);

va_arg gibt den Wert an der Adresse von vl zurück, und zwar mit dem Typ
der als zweites übergeben wird. Wenn wir va_arg also als zweites int über-
geben, gibt er die Zahl von Adresse vl bis Adresse vl+32 zurück (wie wir
wissen ist ein Integer im 32bit windows eben 32-bit gross). Wenn wir als
zweiten Parameter jetzt short oder byte angeben, gibt er nur den Wert von
Adresse vl bis Adresse vl+16 bzw vl+8 zurück. Das funktioniert mit allen
Datentypen. Danach setzt va_arg dann vl automatisch auf Adresse
vl+(size-of-variable)+1, also an den Anfang des nächsten Parameters im
Block. Am Ende müssen wir dann den Zeiger wieder freigeben, sonst droht
die Memory Leak Gefahr. Dafür gibt es das Makro va_end, das foldender-
massen benutzt wird:
Code:
va_end(vl);

Das war dann der ganze Trick. Insgesammt sieht unsere Funktion PrintToFile
dann folgendermassen aus:
Code:
void PrintToFile(char* cText, ...)
{
   char cFromText[256];      // Text den Text für die Verarbeitung zu speichern
   char cToFile[256];      // Text der am Ende in die Datei geschrieben wird
   int nArg;         // Variable um das jeweilige unbekannte Argument zu speichern
   int nFromText;         // Counter um zu Speichern an welcher Position von cFromText wir gerade lesen
   int nToFile;         // Counter um zu Speichern an welcher Position von cToFile wir gerade schreiben
   va_list vl;         // Zeiger vom Typ void*

   cFromText[0]    = '\0';      // Initialisierung
   cToFile[0]    = '\0';      // ""
   nArg       = 0;      // ""
   nFromText   = 0;      // ""
   nToFile      = 0;      // ""
   vl      = 0;      // ""    

   // cText in cFromText kopieren
   sprintf(cFromText,ctext);   
   // auf das das erste Argument nach cText zeigen (beginn vom Block der unbekannten Argumente)
   va_start(ap,error);
   // nach Platzhaltern für Zahlen im Text suchen (wir benutzen #d)
   while(cFromtext[nFromText] != '\0')
   {
      // #d?
      if(cFromText[nFromText] == '#' && cFromText[nFromText+1] == 'd')
      {
         // erste Zahl holen
         nArg = va_arg(vl,int);
         // Zahl zu String konvetieren
         itoa(nArg,cdcml,10);
         // Zahl in cToFile kopieren
         for(unsigned int i=0;i<strlen(cdcml);i++)
         {
            // Buchstabe von cdcml nach cToFile kopieren
            cToFile[nToFile] = cdcml[i];
            // counter erhöhen
            nToFile++;
         }
         // counter erhöhen (#d sind 2 Zeichen, also um 2 erhöhen)
         nFromFile += 2;
      }
      // kein #d, also einfach Zeichen kopieren
      else
      {
         // zeichen von cFromText nach cToFile kopieren
         cFromtext[nFromText] = cTofile[nToFile];
         // counter erhöhen
         nFromText++;
         // counter erhöhen
         nTofile++;
      }
   }
   // aufräumen
   va_end(vl);
   
   // in Datei schreiben
   Print(cToFile);
   
   // return
   return;
}

Die Funktion Print öffnet eine Datei und hängt cToFile an, dann schliesst sie
die Datei und wir sind fertig.
die Makros va_start, va_arg und va_end brauchen den Standardheader <cstdarg.h>
die Funktion itoa() wird im Standardheader <stdlib.h> definiert.

Wer Rechtschreibfehler findet, darf sie behalten.

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
para
DwH Elite
DwH Elite



Anmeldungsdatum: 18.06.2005
Beiträge: 661
Wohnort: Asendorf
Beitrag Verfasst am: 25.11.2005, 01:02    Titel:  Benutzer-Profile anzeigen 

Also ich tue mich ja immer sehr schwer zwischen diesen ganzen Variablen und Parametern den Sinn und Zweck des ganzen zu sehen. Sehr glücklich
Ich denk mir immer, daß das doch viel einfacher gehen müßte. ^^
Aber wahrscheinlich würde man sich damit der Möglichkeiten berauben.

Auch, wenn ich keine Ahnung hab, hab es mir mal durchgelesen hrhr, jedenfalls haste dir ja viel Mühe gegeben den schönen langen Text zu schreiben.

Well done. Smilie -- nice --

_________________
"Let's evolve."

Dr. Jan Nickel Breitenbach rät: "Verschmähen Sie den Doppelkäse nicht."
Antworten mit Zitat 
   Private Nachricht senden            
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 25.11.2005, 14:48    Titel:  Benutzer-Profile anzeigen 

Jep nicht schlecht Winken also ich persönlich mach das mit nem pointer auf nen char array dem ich keine länge zuweise aber feste trennzeichen verwende, soo kann man sich eine funktion schreiben die die allen parameter iterativ mit den trennzeichen an den char anhängt und auch wieder auflösen kann...soo kann man auch eine unbestimmte anzahl von parametern in eine funktion schicken...aber das von exo kannte ich noch nicht und ist die bessere variante...mal schaun wann ich das mal wieder brauche.....

ajo hab mich derletzt an nem programm verkünstelt und mein ganzes können unter beweis gestelllt....das programm wird alles in den schatten stellen...heir der source:

Code:

#inlude <iostream.h>
#pragma hdrstop

int main (void)
{
  cout << "Hello World";
  System("PAUSE");
}


^^geil was???

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 25.11.2005, 22:51    Titel:  Benutzer-Profile anzeigen 

Da hab ich was besseres, der einfachste Virus der Welt:

Code:
int main(void)
{
     int *p_leak;
     while(true)
     {
         p_leak = new int;
      }
      return 0;
}


last es mal nebenher laufen und schaut ab und an ma auf die grösse eurer
virtuellen Auslagerungsdatei. (wenn der PC dann lahm wird, einfach Neustart,
das leert den Auslagerungsspeicher und das Problem ist behoben. Wenn
man die Sache noch langsamer timed, und natürlich verschiedene Versteck
und Autostartmethoden einbaut, kann man damit Leute echt nerven, wenn
nach ca 2 Stunden der PC zu schleichen anfängt. Das System nennt man
übrigens Memory Leak, und eigentlich ist das ein häufig gemachter Fehler
den man vermeiden sollte. Code ist selbsterklärend denke ich, und Warfox
sollte den noch von der Lan kennen :P

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 27.11.2005, 17:28    Titel:  Benutzer-Profile anzeigen 

hehe jep...der ist cool und irgendwann geht nix mehr...aber wie war das eine nomal....

Code:

int main (void)
{
  int * a;
  int b;
  int c;
  a = &b;
  while true
  {
    c++;
    a = &b + c;
    a = 0;
  }
}


das sollte doch eigentlich den arbeitsspeicher leeren oder?=??

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 27.11.2005, 19:03    Titel:  Benutzer-Profile anzeigen 

Nur den Arbeitsspeicher deines Programms, ein non-system Programm
kann nicht auf den kompletten Arbeitsspeicher zugreifen (zumindest
seit win98 se. Unter früheren Versionen sind so lustige Sachen noch recht
simpel möglich). In neueren Windowssystemen muss man schon tricksen
um wirklich Schaden anzurichten. Die memory leaks sind eine der letzten
Methoden die nicht komplett abgefangen werden. Wenn man Assembler
lernt, bekommt man früher oder später mit, das das programm nur den
Speicher kennt, den es zugewiesen bekommt. Es schreibt also an adresse
0x000000 im speicher (der anfang), windows addiert jedoch die adresse
in der das programm im tatsächlichen speicher sitzt zu jeder operation.
so ist es unmöglich den adressbereich zu unterschreiten. beim überschreit-
en sollte man eigentlich einen assertion failure bekommen, wobei ich das
nie so versucht habe. kannst ja mal testen.

PS: du musst natürlich b zuerst auf offset 0x000000 setzen, also 0, damit
er auch am anfang des speichers schreibt. und nen kleinen fehler hast du
auch noch gemacht. vielleicht findest du ihn selbst :P

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 28.11.2005, 12:03    Titel:  Benutzer-Profile anzeigen 

hmmm die klammer vergessen????

janee ich will ja net den windows speicher leeren sondern den speicher ab dem meinem programm istl....also auch den von anderen programmen, das dürfte sicher zu nem bluescreen führen oder???

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 28.11.2005, 23:05    Titel:  Benutzer-Profile anzeigen 

Wie gesagt, wenn du versuchst den zugewiesenen Speicher zu überschreiten,
bekommst du ziemlich sicher nen Assertion Failure, in allen Versionen nach
Win98.

Zitat:

c++;
a = &b + c;
a = 0;


zuerst willst du "a" die Adresse der nächsten Speicherstelle zuweisen, dann
weisst du "a" 0 zu. D.h. alles was du tust ist "a" auf &b+c zeigen zu lassen,
und dann (Fehler) weisst du "a" 0 als Adresse zu. Schreiben tut der gar nix,
er ändert nur ständig die Adresse auf die "a" zeigt.

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 29.11.2005, 10:24    Titel:  Benutzer-Profile anzeigen 

ops dann müsste das ja *a = 0 heißen oder??? häää nee &d = *a + 1; d = 0;oder???

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 29.11.2005, 23:18    Titel:  Benutzer-Profile anzeigen 

Reference operator &(adresss of)b
Dereference operator *(value pointed by)a

Code:
a = &b + c;
*a = 0;


Wichtig:
Code:
int *a = 1000; // setzt a auf die adresse 1000
int *a;
*a = 1000;  // schreibt 1000 an die adresse von a

D.h. Bei der Zeigerdeklaration bewirkt das '*' nur das a ein Zeiger ist. Wenn
man an die Adresse von a etwas schreiben will, muss man das separat nach
der Zeigerdeklaration machen.

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 29.11.2005, 23:36    Titel:  Benutzer-Profile anzeigen 

hmm habs glaub geblickt...mal ausprobieren

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 30.11.2005, 01:26    Titel:  Benutzer-Profile anzeigen 

Um noch mehr zu verwirren gibts dann noch Zeiger auf Zeiger....

Code:
int a;
int b*;
int c*;
b = &a;
c = &b;
**c = 10;


Bewirkt das a auf 10 gesetzt wird. b zeigt auf a, c zeigt auf b. Das kann
beliebig erweitert werden.

Und noch was:
Code:
int *a, b;

a ist ein zeiger auf einen Integer, b jedoch ist eine reine Integervariable.
Um 2 Zeiger zu deklarieren muss für jeden extra ein '*' gesetzt werden.
Code:
int *a, *b;

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 30.11.2005, 10:16    Titel:  Benutzer-Profile anzeigen 

Hehe das kenn ich schon Winken hmm aber damals inder schule war das beste als ich meine funktionen in ne header datei geschrieben habe und dann meine lehrerin sehen wollte was ich denn alles gemacht hab:

Code:


#include <iostream.h>
#include <qwertzgxi.h>

int main (void)
{
  Hausaufgabe01();
  getchar();
}


noja sie war nicht gerade begeister *g*

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Exodus
DwH Elite
DwH Elite



Anmeldungsdatum: 25.07.2004
Beiträge: 278
Wohnort: n/a
Beitrag Verfasst am: 30.11.2005, 11:20    Titel:  Benutzer-Profile anzeigen 

Inkompetenz. Je kleiner die Hauptprogrammschleife desto besser.
Das ist guter Programmierstil. Das ist auch der Grund warum ich neue
Projekte nie von der IDE kreieren lasse. Gegen so viel Chaos in Quell-
codedateien bin ich echt allergisch.

_________________
crush hope
shatter dreams
enjoy the torture
search the truth
enforce your reign
head for glory
reach immortality
and finally...fall
as failure is the human fate
run for the fall
Antworten mit Zitat 
   Private Nachricht senden  E-Mail senden  Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Warfox
DwH Member



Anmeldungsdatum: 12.02.2004
Beiträge: 1612
Wohnort: DWH - Hochburg
Beitrag Verfasst am: 01.12.2005, 07:34    Titel:  Benutzer-Profile anzeigen 

jop...sind halt lehrer die lehren was sie können......

_________________
Warfox...what else?
Antworten mit Zitat 
   Private Nachricht senden    Website dieses Benutzers besuchen  AIM-Name  Yahoo Messenger  MSN Messenger  ICQ-Nummer
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    -=]Die with Honor[=- Foren-Übersicht » Hard & Softwareecke Alle Zeiten sind GMT + 1 Stunde
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum nicht posten
Du kannst Dateien in diesem Forum herunterladen


Powered by phpBB © 2001, 2005 phpBB Group
Created by: __ Infected-FX __