Dateien einlesen und vergleichen



  • Korrekt!

    Der String ist konstant -> konstant != variabel -> also nicht änderbar



  • Funktion funktioniert zwar, aber nicht richtig. Man beachte beim Orginal verbleibt das Ende des Strings in ersten Parameter, bei der neuen verbleibt dies im zweiten Parameter.

    Die Funktion scheint aber schneller zu sein. 🙂

    Korrektur:

    Begin test1 Orginal-Funktion
    End test1: 0.256421 Sekunden
    Begin test2 Neue Lösung
    End test2: 0.332843 Sekunden
    Begin test3 Leere Schleife
    End test3: 0.070380 Sekunden

    #define NUM 1000000
    void test3(void)
    {int i;
     char Peter[129];
     char Peter1[129];
     APPLTraceB(APPLV1,"test3")
     for (i=0;i<NUM;i++)
      {
      strcpy(Peter,"Dies ist ein Test,hier der zweite Teil");
      _substr_(Peter,Peter1,','); //substr, substr_
      }
      APPLTraceE(APPLV1,"test3")
    }
    

    Eine lösung für die zweite wäre noch viel interessanter! 😃



  • @PAD
    Darum ist die "neue" auch schneller, weil nur 1 mal rumkopiert wird (könnte man sich übrigens auch sparen, wenn man es etwas anders verarbeitet -> noch schneller).

    Die zweite würde ich so lösen:

    char *entfWSC(char *text)
    {
       char *pos;
    
       for(pos = text; *pos && isspace(*pos); ++pos); //kann man sich leider nicht ersparen ;)
    
       if(pos != text)
          strcpy(text, pos);
    
       return(text);
    }
    


  • Ich musste leider meine Aussage korrigieren die Orginal-Implementierung ist bei mir schneller.

    Ergebnisse in Sekunden
    Start of applikation part
    Begin test1
    End test1: 0.256003 Orginal
    Begin test2
    End test2: 0.329853 Neue Implementierung
    Begin test3
    End test3: 0.072492 Leer Schleife
    Begin test4
    End test4: 0.453790 entfWSC
    Begin test5
    End test5: 0.577858 StrRmLe
    End of applikation part
    ReturnCode: 0
    System Shutdown

    Das lohnt sich



  • Wie oft hast du es denn probiert?

    Möglicherweise bremst strcpy() das ganze etwas aus. Ich wäre aber eigentlich davon ausgegangen, dass es auch nicht viel mehr macht als deine Kopierschleife. 😕



  • Das Testprogramm hat so um die 100 Läufe mit vergleichbaren Ergebnissen unter Win2000 gebracht.
    Insgesamt habe ich diese 5 Testfunktionen jede 1 000 000 Mal aufgerufen in MSVC 6.0 release version speed optimiert.

    Die Funktion test3 sieht wie folgt aus und dient dazu den Overhead zu bestimmen.
    Als Timer wird der HIGH-Performance Timer benutzt

    int dummi(char *quelle, char *ziel, char suche)
    {
    	return 0;
    }						   
    
    void test3(void)
    {
    	int i;
    	char Peter[129];
    	char Peter1[129];
        APPLTraceB(APPLV1,"test3")
    	for (i=0;i<NUM;i++)
    	{
    		strcpy(Peter,"Dies ist ein Test,hier der zweite Teil");
    		dummi(Peter,Peter1,',');
    	}
      APPLTraceE(APPLV1,"test3")
    }
    


  • ich muss aber leider zu geben, dass der Code, bzw. die Funktionen von PAD wesentlich besser funktionieren. Wenn ich bei AJ's Code mir die einzelnen Teile ausgeben lasse, dann bekomme ich nur so ein Schmarn hier:

    input   :    1   A_ID=166
    part1     :  ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
    ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠  1   A_ID=166
    part2     :  ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
    ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
    

    bei dem Code von PAD klappt es wunderbar (sprich: input wird genau in diese Teile zerlegt), der ist aber schwerer zu verstehen finde ich... Woran könnte das wohl liegen?
    Und was ist eigentlich das hier? Da verstehe ich ja nur Bahnhof:

    #define NUM 1000000
    void test3(void)
    {int i;
     char Peter[129];
     char Peter1[129];
     APPLTraceB(APPLV1,"test3")
     for (i=0;i<NUM;i++)
      {
      strcpy(Peter,"Dies ist ein Test,hier der zweite Teil");
      _substr_(Peter,Peter1,','); //substr, substr_
      }
      APPLTraceE(APPLV1,"test3")
    }
    

    Hat das auch irgendwas mit meiner Frage zu tun? Würde mich über einige Kommentare mehr freuen. Danke



  • @Jerry
    Wie ist denn der Aufruf bei meiner Funktion und die Ausgabe?



  • So rufe ich deine Funktion auf:

    char input[MAX_LEN]="1   A_ID=166234"; 
    	char part1[80+1]; 
    	char part2[80+1]; 
    
    	printf("\ntestline:  %s\n",input);
    
    	sub(input,part1,' ');  
    	entfWSC(input); 
         sub(input,part2,'=');       		
    
    	printf("input     :  %s\n",input);
    	printf("\npart1   :  %s\n",part1);
    	printf("part2     :  %s\n",part2);
    

    und wenn ich mir nun die Ausgabe angucke kommt genau das raus, was ich eben schon gepostet habe, nur dass "╠" immer ein seltsames Zeichen ist, d.h. dort steht nicht immer diese zahl, sondern ein Zeichen.



  • Seltsam, ich hab grad folgendes

    #include <stdio.h>
    #include <string.h>
    
    int substr(char *quelle, char *ziel, char suche);
    
    int main(int argc, char **argv)
    {
      char text[100] = "Text=Wert";
      char wert[20];
    
      substr(text, wert, '=');
    
      printf("%s = %s", text, wert);
    
      return 0;
    }
    
    int substr(char *quelle, char *ziel, char suche)
    {
       char *pos;
    
       //Zeichen suchen
       pos = strchr(quelle, suche);
    
       //Zeichen gefunden?
       if(pos)
       {
          //gefundenes Zeichen überschreiben
          *pos++ = 0;
    
          //alles nach dem gefundenen Zeichen kopieren
          strcpy(ziel, pos);
    
          return(0); //Alles OK
       }
       else
       {
          return(-1); //Suchzeichen nicht gefunden!
       }
    }
    

    hiermit compiliert und das Programm ausgeführt. Funktioniert problemlos.



  • das stimmt. wenn ich deinen Code compiliere klappt das auch. in meinem Programm klappt das nicht.
    Naja, ich werde mal noch ein wenig rumfuchsen und denn mal sehen, ob ich es noch hinbekomme.
    Auf jeden Fall schon mal Danke.



  • Die Funktionen von AJ funktionieren bei mir einwandfrei. nur sein substr liefert die Ergebnisse anders zurück als mein substr.

    Die Funktion test3 sollte hat mit deinem Problem nichts zu tun. Sie dient nur dazu zu zeigen wie
    ich den Overhead der Funktionen ermittelt habe um die Laufzeiten der Funktionen
    substr alt, substr neu, StrRmLe und entfWSC zu ermitteln. in den Funktionen test1,test2,test4, test5 war jeweils eine der zu testenden funktionen anstelle der leerfunktion _substr_. Es ging nicht andersden wenn ich diese dummi Funktion weglasse ärgert mich der optimizer des Compilers.

    😉 Danke AJ, zumindest habe ich jetzt eine schnellere Variante mit entfWSC 😉

    Diese zwei Funktionen sind zentraler Bestandteil einer großen Anzahl von Textmanipulationstools
    bei zu Hause und in meinem Job, und meine Meinung ist je schneller desto besser solange die Verständlichkeit
    nicht leidet.

    Damit die beiden substr Varianten sich gleich verhalten müssen bei AJ die mit /**/ markierten Zeilen geändert werden.
    Denn leider ist es das entscheidende an dieser Funktioen das der Inputstring vom Anfang her um die gefundenen Zeichen verkürzt wird und diese in Ziel auftauchen. Somit kann man auf übersichlichste Weise einen Inputstring mit verschiedenen Trennzeichen in seine Bestandteile zerlegen.

    int substr_(char *quelle, char *ziel, char suche)
    {
       char *pos;
       char *tmp;
       //Zeichen suchen
       pos = strchr(quelle, suche);
    
       //Zeichen gefunden?
       if(pos)
       {
          //gefundenes Zeichen überschreiben
          *pos++ = 0;
    
    /**/       //Ergebnis d.h der Teil vor dem Trennzeichen nach Ziel kopieren
    /**/  	  strcpy(ziel,quelle);
    /**/       //alles nach dem gefundenen Zeichen kopieren
    /**/       strcpy(quelle, pos);
          return(0); //Alles OK
       }
       else
       {
          return(-1); //Suchzeichen nicht gefunden!
       }
    }
    


  • Habe jetzt noch einmal die Laufzeiten verglichen mit MS Visual C++ 6.0 professional, mit interessanten
    Ergebnissen.

    Einmal in der Debugversion

    Anzahl Durchlaeufe: 67108864 0x4000000
    Begin test1 dummi (Overhead) End test1: 7.857198
    Begin test2 substr alt PAD End test2: 48.689702
    Begin test3 substr neu AJ End test3: 26.469494
    Begin test4 entfWSC End test4: 21.819640
    Begin test5 StrRmLe End test5: 56.789122
    Test1 Ges: 7.857 Kor: 0.000 s, pro Run: 0.000 us
    Test2 Ges:48.690 Kor:40.833 s, pro Run: 0.608 us
    Test3 Ges:26.469 Kor:18.612 s, pro Run: 0.277 us 👍
    Test4 Ges:21.820 Kor:13.962 s, pro Run: 0.208 us 👍
    Test5 Ges:56.789 Kor:48.932 s, pro Run: 0.729 us

    Einmal in der Releasversion Speed Optimiert

    Anzahl Durchlaeufe: 67108864 0x4000000
    Begin test1 dummi (Overhead) End test1: 4.062547
    Begin test2 substr alt PAD End test2: 16.711492
    Begin test3 substr neu AJ End test3: 33.469272
    Begin test4 entfWSC End test4: 29.972967
    Begin test5 StrRmLe End test5: 37.763907
    Test1 Ges: 4.063 Kor: 0.000 s, pro Run: 0.000 us
    Test2 Ges:16.711 Kor:12.649 s, pro Run: 0.188 us
    Test3 Ges:33.469 Kor:29.407 s, pro Run: 0.438 us 👎
    Test4 Ges:29.973 Kor:25.910 s, pro Run: 0.386 us 👎
    Test5 Ges:37.764 Kor:33.701 s, pro Run: 0.502 us



  • @PAD
    Also wenn es dir um Schnelligkeit geht, dann hätt ich noch ne schnellere Variante für deine Teilerfunktion:

    void teiler(char **quelle, char **teil, char suche)
    {
       char *pos;
    
       for(pos = *quelle; *pos && *pos != suche; ++pos);
    
       if(*pos)
       {
          *pos++ = 0;
          *teil = *quelle;
          *quelle = pos;
       }
    }
    

    Allerdings musst du dann beim Aufruf mit variablen Zeigern arbeiten:

    ...
    char text[20] = "Text=Wert";
    char *name, *wert;
    
    wert = text;
    teiler(&wert, &name, '=');
    
    printf("Name: %s\nWert: %s\n", name, wert);
    

    Warum müssen die Parameter eigentlich in dieser unvorteilhaften Verteilung sein??

    PS: Die Schleife oben kann man auch durch strchr() ersetzen: pos = strchr(*quelle, suche);

    Also diese Geschwindigkeitsergebnisse finde ich sehr seltsam. Besonders, weil im Debugmodus meine Funktionen schneller sind. 😕



  • Weil wenn ich substr, eine Funktion die bei uns in einer Tool-Bibliothek seit zig Jahren verankert ist,
    durch eine moderne Variante ersetze, diese Form Fit Funktion kompatibel sein muss.

    input: " test1,360.0,a:b20:c30,t:20,450 "

    dies sich leicht durch folgende Sequenz zerlegen läst, es ist übersichtlich den Rest input stehen zu haben

    substr(input,testname,',');
    substr(input,position,',');
    substr(input,p1,':');
    substr(input,p2,':');
    substr(input,p3,',');
    substr(input,dummi,':');
    substr(input,Temperatur,','); // in Input steht jetzt noch 450

    Hier 2 Beispiele aus der realen Welt
    HEHDT,338.0,T26HEHDT,338.0,T*26 GPGGA,161330.00,5955.10,N:02452.48,E:2,00,0.0,0.0,M,0.0,M,0.0,0000*77

    Die sonst nötige Abfolge ist deutlich unübersichtlicher
    teil(input,rest,',');
    strcpy(testname,input);
    teil(rest,input,',');
    strcpy(position,rest);
    teil(input,rest,':');
    strcpy(p1,rest);
    ....

    Die Funktion Teiler sieht sehr interessant aus

    Debug
    Begin test6 teiler End test6: 22.198350
    Test6 Ges:22.198 Kor:13.926 s, pro Run: 0.208 us
    Release
    Begin test6 teiler End test6: 10.375988
    Test6 Ges:10.376 Kor: 6.320 s, pro Run: 0.094 us

    Bleibt nur eine Frage wie vermeide ich die beiden strcpy´s // Form Fit Funktion

    double test6(void)
    {	int i;
    	char Peter[129];
    	char Peter1[129];
    	char *name, *wert; 
        APPLTraceB(APPLV1,"test6 teiler")
    	for (i=0;i<NUM;i++)
    	{
    	strcpy(Peter,"			  ist ein Test,hier der zweite Teil");
    	wert=Peter;
    	teiler(&wert,&name,',');
    /**/    strcpy(Peter1,name);
    /**/    strcpy(Peter,wert);
    	}
      APPLTraceETa(APPLV1,"test6")
    }
    


  • Auf die Art kannst du das strcpy() schlecht vermeiden.

    Ich hab auch mal was mit dem NMEA-Protokoll vom GPS-Empfänger machen dürfen. Ich bin das damals, glaub ich, mit strchr() durchgegangen, hab die Trenner immer mit 0 überschrieben und die einzelnen Inhalte in eine Struktur gesteckt (als Zahlen hald ;)).



  • Das NMEA Protokoll ist nur ein Beispiel von vielen, in denen wir ASCII-Dateien "interpretieren" um Daten
    Auswertung zu betreiben.
    Aber Interessant, das du es auch kennst



  • Ich musste die Daten des GPS-Empfängers auswerten und auf einem Handheld-PC ausgeben (zum Glück nur Text). Durch die Programmierung des Handhelds hab ich einige Erfahrung mit seriellen Schnittstellen und anschließbaren Geräten gesammelt. Ich musste dann auch mal einen GPS-Simulator schreiben. Der hatte einen Start und Endpunkt und musste dann von dem einen Punkt zum anderen fahren. Sogar die Geschwindigkeit musste sich regulieren lassen. War ganz interesant.



  • Da ich in der Testgeräteentwicklung einer Navigationsfirma arbeite, habe des ständig mit solchen und
    vielen ähnlichen Problemen zu tun.

    Es sind Prüfprogramme und Simulatoren für unsere Produkte zu entwickeln, damit man bei diesen sowohl die Designtests als auch die Endkontrolle sinnvoll durchführen kann



  • PS: falls einer für StrRmLe eine bessere Implementierung weis, ich bin neugierig?

    ich würds so machen

    void StrRmLe(char *s){
    int x=strlen(s);
    for(char *p=s;isspace(*p);++p);
    if(p-s)memmove(s,p,x+1-(p-s));
    }
    

Anmelden zum Antworten