Peter: String concat in c++

Hallo,

Ich schäme mich ja ein wenig diese Frage hier zu stellen, aber ich suche seit stunden rum und finde nichts dazu. Ich habe früher hauptsächlich java u.ä programmiert und jetzt gezwungernermaßen c++.
Nur bekomme ich die simpelste Aufgabe nicht hin...Ich will einen Dateinamen zusammensetzen aus ein paa variablen, also aus char* und aus ein paar int-werten. So einfach geht das ja nun leider nicht, wie ich gemerkt habe. Der + operator funktioniert nicht für char, strcat funktioniert nicht für char pointer und int werte lassen sie eh nicht in char* casten wie es mir vorkommt...kann mir jemand helfen ?

das Problem in einfachen Worten :
Strings zusammensetzen aus einzelnen chars* vermischt mit ints ...

Vielen Dank !

Gruss
 Peter

  1. 你好 Peter,

    benutze die Standard-Klassen von C++, in diesem Fall dürfte dir std::string
    am Meisten weiterhelfen. Ansonsten gilt auch hier: das Lesen wird dir keiner
    abnehmen können.

    再见,
     克里斯蒂安

    --
    Block-Installation Nr. 5 | Renovation der Mensa-Nord
    Nur die Weisesten und die Dümmsten können sich nicht ändern.
    http://wwwtech.de/
  2. Hallo Peter,

    Hans="Peter"
    i=1
    my_floar=3.15

    sprintf(dateiname,"%s,%d,%f",hans,i,my_float);

    dateiname="Peter,1,3.15"

    Gruß

    Hans

    1. 你好 Hans,

      Hans="Peter"
      i=1
      my_floar=3.15

      sprintf(dateiname,"%s,%d,%f",hans,i,my_float);

      Astreiner Speicherzugriffsfehler.

      再见,
       克里斯蒂安

      --
      Block-Installation Nr. 5 | Renovation der Mensa-Nord
      If God had a beard, he'd be a UNIX programmer.
      http://wwwtech.de/
      1. morning,

        Hans="Peter"
        i=1
        my_floar=3.15

        sprintf(dateiname,"%s,%d,%f",hans,i,my_float);

        Astreiner Speicherzugriffsfehler.

        es ist zwar nicht gerade bullet proof(buffer overflow etc.) aber IMHO faulen
        die Segmente hier nicht weg. Wie kommst du drauf?

        cya
         -T

        1. 你好 neri,

          Astreiner Speicherzugriffsfehler.
          es ist zwar nicht gerade bullet proof(buffer overflow etc.) aber IMHO
          faulen die Segmente hier nicht weg. Wie kommst du drauf?

          Du hast einfach zu wenig Code gepostet. Dein Code lässt einen Anfänger vermuten, er könne auf char *-Variablen einfach so zugreifen, ohne Speicher
          zu alloziieren oder sonstwas. Deshalb meine Bemerkung.

          再见,
           克里斯蒂安

          --
          Block-Installation Nr. 5 | Renovation der Mensa-Nord
          Kommt ein Nullvektor zum Psychiater: "Herr Doktor, ich bin orientierungslos!"
          http://wwwtech.de/
      2. Hallo Christian,

        sprintf(dateiname,"%s,%d,%f",hans,i,my_float);
        Astreiner Speicherzugriffsfehler.

        wenn man mal von den syntaktischen Fehlern (fehlende Semikola bei den Zuweisungen) und den Schreibfehlern bei den Variablennamen (nicht nur, aber auch Groß/Kleinschreibung) absieht, ist das eigentlich okay. Vorausgesetzt, dateiname ist groß genug dimensioniert, um alle gewünschten Daten, vor allem den String, aufzunehmen. Das hat neri ja auch schon angedeutet.

        Also wo siehst du hier den kapitalen Bock?
        So long,

        Martin

        --
        Denken ist wohl die schwerste Arbeit, die es gibt. Deshalb beschäftigen sich auch nur wenige damit.
          (Henry Ford, amerikanischer Industriepionier)
        1. Hi Der!

          Also wo siehst du hier den kapitalen Bock?

          Hast du doch selbst schon gesagt:

          Vorausgesetzt, dateiname ist groß genug dimensioniert

          Ich sehe nur, dass dateiname gar nicht dimensioniert ist.

          MfG H☼psel

          --
          "It's amazing I won. I was running against peace, prosperity, and incumbency."
          George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
          Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
        2. Moin!

          sprintf(dateiname,"%s,%d,%f",hans,i,my_float);
          Astreiner Speicherzugriffsfehler.

          wenn man mal von den syntaktischen Fehlern [...] und den Schreibfehlern bei den Variablennamen [...] absieht, ist das eigentlich okay.

          Nein, ist es nicht. Du willst nicht wirklich sprintf in deinem Code verwenden, sondern snprintf.

          Vorausgesetzt, dateiname ist groß genug dimensioniert, um alle gewünschten Daten, vor allem den String, aufzunehmen.

          Ich zitiere hier aus der BSD Library Functions Manual über sprintf(3):

          SECURITY CONSIDERATIONS

          The sprintf() and vsprintf() functions are easily misused in a manner which enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack.  Because sprintf() and vsprintf() assume an *infinitely long string*, callers must be careful not to overflow the actual space; this is often hard to assure.  For safety, programmers should use the snprintf() interface instead.

          Also wo siehst du hier den kapitalen Bock?

          Das sprintf halt – wie genannt – davon ausgeht, dass dein Puffer im Zweifelsfall unendlich groß ist. Deshalb will man z.B. auch gets nicht benutzen, sondern fgets(buffer, buffsize, stdin) stattdessen.

          Viele Grüße,
          Robert

          1. Hallo Robert,

            wenn man mal von den syntaktischen Fehlern [...] und den Schreibfehlern bei den Variablennamen [...] absieht, ist das eigentlich okay.
            Nein, ist es nicht. Du willst nicht wirklich sprintf in deinem Code verwenden, sondern snprintf.

            Also, wenn ich ehrlich bin: Von snprintf() habe ich noch nie gehört.

            Also wo siehst du hier den kapitalen Bock?
            Das sprintf halt – wie genannt – davon ausgeht, dass dein Puffer im Zweifelsfall unendlich groß ist.

            Natürlich. Das ist mir geläufig und so selbstverständlich, dass ich es hier nur indirekt am Rande erwähnt habe. Das trifft auch auf die (mir besser vertraute) Windows API-FUnktion wsprintf() zu, bei der ich als Programmierer ja auch dafür sorgen muss, dass mein Puffer groß genug ist. Die allgemeine Sorgfaltspflicht obliegt schließlich immer dem Programmierer.

            Schönen Tag noch,

            Martin

            --
            Paradox ist, wenn der Innenminister sich äußert und der Außenminister sich erinnert.
            Schon Urlaubspläne?
            1. Moin Martin!

              Nein, ist es nicht. Du willst nicht wirklich sprintf in deinem Code verwenden, sondern snprintf.

              Also, wenn ich ehrlich bin: Von snprintf() habe ich noch nie gehört.

              In der zitierten Handbuchseite steht, dass snprintf zu ISO C99 gehört, was leider nicht alle Compiler unterstützen, während sprintf konform zu ANSI C ist, was wohl jeder Compiler versteht.

              Also wo siehst du hier den kapitalen Bock?
              Das sprintf halt – wie genannt – davon ausgeht, dass dein Puffer im Zweifelsfall unendlich groß ist.

              Natürlich. Das ist mir geläufig und so selbstverständlich, dass ich es hier nur indirekt am Rande erwähnt habe. Das trifft auch auf die (mir besser vertraute) Windows API-FUnktion wsprintf() zu, bei der ich als Programmierer ja auch dafür sorgen muss, dass mein Puffer groß genug ist.

              Wie bekommt man denn dort dieses Problem in den Griff? Wahrscheinlich genauso wenig, wie bei der Verwendung von sprintf. Ich verstehe mit wachsender Programmier-Erfahrung nicht, wie es sein kann, dass solche Funktionen wie sprintf überhaupt noch als kleinster gemeinsamer Nenner zu einem Sprachstandard gehören, obwohl es deutlich sicherere Varianten gibt. IMHO ist die Stringbehandlung in C der Hauptgrund dafür, dass tonnenweise unsicherer C-Code geschrieben wurde und immer noch wird.

              Die allgemeine Sorgfaltspflicht obliegt schließlich immer dem Programmierer.

              Wenn der allerdings nach eigener Aussage die ersten Gehversuche mit C macht – und vorher auch noch mit Java programmiert hat – dann haben wir als Teilnehmer dieses Forums meiner Meinung nach die Sorgfaltspflicht ihm gegenüber, korrektes, sicheres Programmieren in C beizubringen. Er soll ja nicht gleich auf einmal alle Möglichkeiten finden, sich in den Fuß zu schießen.

              Viele Grüße,
              Robert

              1. Hallo Robert,

                In der zitierten Handbuchseite steht, dass snprintf zu ISO C99 gehört, was leider nicht alle Compiler unterstützen, während sprintf konform zu ANSI C ist, was wohl jeder Compiler versteht.

                Ach so, also ist snprintf() noch etwas ziemlich neues. Kein Wunder, dass ich es nicht kenne.

                auf die [...] Windows API-Funktion wsprintf() zu, bei der ich als Programmierer ja auch dafür sorgen muss, dass mein Puffer groß genug ist.
                Wie bekommt man denn dort dieses Problem in den Griff?

                Ganz einfach durch eine worst-case-Abschätzung. Wenn ich Zahlenwerte mit xxprintf() ausgebe, sollte ich als Autor des Programmcodes wissen, in welchen Grenzen diese Zahlen liegen können - abgehakt. Im Fall von Strings ergibt sich die maximale Länge oft auch aus Beschränkungen, die im restlichen Programm irgendwo abgeprüft werden; in anderen Fällen gibt es strlen() oder die Möglichkeit, %s mit einer Längenangabe zu versehen.

                Ich verstehe mit wachsender Programmier-Erfahrung nicht, wie es sein kann, dass solche Funktionen wie sprintf überhaupt noch als kleinster gemeinsamer Nenner zu einem Sprachstandard gehören, obwohl es deutlich sicherere Varianten gibt. IMHO ist die Stringbehandlung in C der Hauptgrund dafür, dass tonnenweise unsicherer C-Code geschrieben wurde und immer noch wird.

                Hmm. Ich bin da wohl aus anderem Holz geschnitzt. Ich liebe die Freiheit, die C mir bietet, auch wenn sie gewisse Risiken birgt. Oft geht mir sogar diese Freiheit nicht weit genug, so dass ich mich über Beschränkungen der Sprache an sich oder eines bestimmten Compilers ärgere (Stichwort Typkompatibilität). Vielleicht liegt's daran, dass ich jahrelang Assembler programmiert habe und da erst die _wirkliche_ Programmierer-Freiheit kennen und lieben gelernt habe?

                Die allgemeine Sorgfaltspflicht obliegt schließlich immer dem Programmierer.
                Wenn der allerdings nach eigener Aussage die ersten Gehversuche mit C macht ...

                Oh, ich bitte um Entschuldigung. Das hatte ich tatsächlich schon wieder vergessen.
                Noch schlimmer: Er benutzt nicht C, sondern C++, das ich sonst normalerweise meide wie der Teufel das Weihwasser, weil es die (im Gegensatz zu strengeren Sprachen wie z.B. Pascal) schon relativ laxen Syntaxregeln von C noch weiter aufweicht und mehr noch als C zu schlampigem Code verführt.
                Wobei man in C durchaus sehr sauberen und übersichtlichen Programmcode schreiben kann, wenn man sich ein wenig am Riemen reißt.

                Schönen Abend noch,

                Martin

                --
                why the heck do you jerk think, that wir ein doppelposting nicht bemerken, wenn you zwischendurch the sprache wechselst?
                  (wahsaga, http://forum.de.selfhtml.org/?t=110904&m=697006, nicht archiviert)
                Schon Urlaubspläne?
                1. Moin Martin!

                  In der zitierten Handbuchseite steht, dass snprintf zu ISO C99 gehört, was leider nicht alle Compiler unterstützen, während sprintf konform zu ANSI C ist, was wohl jeder Compiler versteht.

                  Ach so, also ist snprintf() noch etwas ziemlich neues. Kein Wunder, dass ich es nicht kenne.

                  Deshalb wird diese Funktion wohl bislang auch nicht von jedem C-Compiler angeboten, obwohl es wirklich sinnvoll wäre – angesichts der täglichen Meldungen über Buffer-Overflows in Software.

                  auf die [...] Windows API-Funktion wsprintf() zu, bei der ich als Programmierer ja auch dafür sorgen muss, dass mein Puffer groß genug ist.
                  Wie bekommt man denn dort dieses Problem in den Griff?

                  Ganz einfach durch eine worst-case-Abschätzung.

                  Also im Zweifelsfalle
                  char *buffer = malloc(sizeof(size_t) == 8 ? UINT64MAX : UINT32MAX)
                  ;-)

                  Wenn ich Zahlenwerte mit xxprintf() ausgebe, sollte ich als Autor des Programmcodes wissen, in welchen Grenzen diese Zahlen liegen können - abgehakt.

                  OK, gebongt – float- und double-Werte sind insofern sogar recht praktisch, weil ich da in gewissen Grenzen den Platzverbrauch selbst vorgeben kann. Aber: Wieviele Stellen muss ich denn schlimmstenfalls für einen 64-Bit-Wert vorsehen bzw. welcher Programmierer weiß so etwas?

                  Im Fall von Strings ergibt sich die maximale Länge oft auch aus Beschränkungen, die im restlichen Programm irgendwo abgeprüft werden; in anderen Fällen gibt es strlen()

                  Leider fehlte dies im angesprochenen Beispiel. Ich weiß aus eigener Erfahrung, dass man sich auch in C mit dem Prinzip Hoffnung oft durchmogeln kann (allerdings nur in einem Bruchteil der Fälle verglichen mit z.B. PHP), ohne dass auch nur einmal der Buffer-Overflow zum Tragen käme.

                  oder die Möglichkeit, %s mit einer Längenangabe zu versehen.

                  Zu welchem Standard ist dann denn kompatibel?

                  Ich verstehe mit wachsender Programmier-Erfahrung nicht, wie es sein kann, dass solche Funktionen wie sprintf überhaupt noch als kleinster gemeinsamer Nenner zu einem Sprachstandard gehören, obwohl es deutlich sicherere Varianten gibt. IMHO ist die Stringbehandlung in C der Hauptgrund dafür, dass tonnenweise unsicherer C-Code geschrieben wurde und immer noch wird.

                  Hmm. Ich bin da wohl aus anderem Holz geschnitzt. Ich liebe die Freiheit, die C mir bietet, auch wenn sie gewisse Risiken birgt.

                  Die muss man erst einmal erblicken und dann unter Kontrolle bekommen. Insofern muss man vor den OpenBSD-Leuten echt den Hut ziehen: „Nur ein »remote hole« in der Standardinstallation seit über 8 Jahren!“

                  Oft geht mir sogar diese Freiheit nicht weit genug, so dass ich mich über Beschränkungen der Sprache an sich oder eines bestimmten Compilers ärgere (Stichwort Typkompatibilität).

                  Wie soll ich das denn interpretieren?

                  Vielleicht liegt's daran, dass ich jahrelang Assembler programmiert habe und da erst die _wirkliche_ Programmierer-Freiheit kennen und lieben gelernt habe?

                  Naja, da gibt es ja schon einen größeren Unterschied zwischen Assembler und C, vor allem zu C++. Am besten ist es, die Denkweisen und Paradigmen, die man von der einen Programmiersprache kennt, vollkommen über Bord zu werfen und sich in die Sprache einzudenken, mit der man gerade arbeitet.

                  Die allgemeine Sorgfaltspflicht obliegt schließlich immer dem Programmierer.
                  Wenn der allerdings nach eigener Aussage die ersten Gehversuche mit C macht ...

                  Oh, ich bitte um Entschuldigung. Das hatte ich tatsächlich schon wieder vergessen.

                  Tststs, und so etwas in diesem Forum, wo Programmieranfänger zuschauen. An dieser Stelle zum angesprochenen Beispiel: „The above code is dangerous. For your savety and those around you: Do not try this at home! - No really, don't!“ (Frei nach Braniac)

                  Noch schlimmer: Er benutzt nicht C, sondern C++, das ich sonst normalerweise meide wie der Teufel das Weihwasser, weil es die (im Gegensatz zu strengeren Sprachen wie z.B. Pascal) schon relativ laxen Syntaxregeln von C noch weiter aufweicht und mehr noch als C zu schlampigem Code verführt.

                  Das kann ich nicht bestätigen. Ich kann mittlerweile recht gut C++-Programmieren und ich finde, dass gerade die OOP (in C++) zusammen mit der STL gute Helfer bei der Vermeidung unnötiger Sicherheitslücken, Speicherlecks, … sind. Was ich z.B. zur Stringbehandlung sagte, gilt auch für dynamisch veränderliche Datenstrukturen: Das alles ist mit C++ deutlich sauberer, unkomplizierter und sicherer machbar.

                  Wobei man in C durchaus sehr sauberen und übersichtlichen Programmcode schreiben kann, wenn man sich ein wenig am Riemen reißt.

                  Selbstverständlich! Es kommt halt stark auf die verwendete Einführung in C an: Ich habe die Sprache damals mit einem Buch gelernt, indem der Autor ständig auf der Problematik mit Arrays, Strings und Pointern eindringlich eingegangen ist („dann ist das Verhalten der Funktion undefiniert“, …). Das hat mich ganz gut „erzogen“. Allerdings bezweifele ich, dass das für alle C-Programmierer gilt, zumal selbst große der Branche dämliche Fehler bis in die Doku schleppen: Bei Borland habe ich mal folgendes printf-/readdir-Beispiel gesehen:

                    
                  #include <dirent.h>  
                  #include <stdio.h>  
                    
                  DIR *dirp = opendir(".");  
                    
                  while ((dp = readdir(dirp)) != NULL)  
                      /* write out the files in this directory */  
                      printf(dp->d_name);  
                  }  
                  (void)closedir(dirp);  
                  
                  

                  Das ganze wird natürlich bei %n im Dateinamen spaßig.

                  Viele Grüße,
                  Robert

                  1. Hallo,

                    Ganz einfach durch eine worst-case-Abschätzung.
                    Also im Zweifelsfalle
                    char *buffer = malloc(sizeof(size_t) == 8 ? UINT64MAX : UINT32MAX)
                    ;-)

                    hehe... Mit "worst-case" meinte ich natürlich schon, dass auch programmintern gesetzte Limits berücksichtigt werden dürfen.

                    OK, gebongt – float- und double-Werte sind insofern sogar recht praktisch, weil ich da in gewissen Grenzen den Platzverbrauch selbst vorgeben kann. Aber: Wieviele Stellen muss ich denn schlimmstenfalls für einen 64-Bit-Wert vorsehen ...

                    Moment... 2^32 ist ungefähr 4E+09, 2^64 also rund 16E+18, normalisiert 1.6E+19 oder ±8E+18, also schlimmstenfalls 20 Stellen.

                    bzw. welcher Programmierer weiß so etwas?

                    Jeder, der sich nicht mehr "Anfänger" nennen muss. ;-)

                    [...] in anderen Fällen gibt es strlen()
                    Leider fehlte dies im angesprochenen Beispiel. Ich weiß aus eigener Erfahrung, dass man sich auch in C mit dem Prinzip Hoffnung oft durchmogeln kann

                    Ja, gesundes Gottvertrauen (oder Gelassenheit durch Unwissenheit) ist auch eine Methode, und wie du schon andeutest, treten solche Fehler nur in einem Bruchteil der Fälle wirklich gravierend zutage. Aber mir wäre nicht wohl dabei...

                    oder die Möglichkeit, %s mit einer Längenangabe zu versehen.
                    Zu welchem Standard ist dann denn kompatibel?

                    Standard? Keine Ahnung, frag mich nicht solche Sachen. Mein Compiler (bzw. seine RTL) versteht das jedenfalls und setzt es korrekt um. Und darauf kommt es letzten Endes an.

                    Hmm. Ich bin da wohl aus anderem Holz geschnitzt. Ich liebe die Freiheit, die C mir bietet, auch wenn sie gewisse Risiken birgt.
                    Die muss man erst einmal erblicken und dann unter Kontrolle bekommen.

                    Die Freiheit oder die Risiken? Wie gesagt, die Freiheit weiß ich zu schätzen, und der Risiken bin ich mir größtenteils bewusst, weil ich maschinennah denke und intuitiv den zu meiner C-Anweisung gehörenden Assembler-Code vor Augen habe.

                    Insofern muss man vor den OpenBSD-Leuten echt den Hut ziehen: „Nur ein »remote hole« in der Standardinstallation seit über 8 Jahren!“

                    Das ist allerdings beachtlich. Mein Respekt!

                    Oft geht mir sogar diese Freiheit nicht weit genug, so dass ich mich über Beschränkungen der Sprache an sich oder eines bestimmten Compilers ärgere (Stichwort Typkompatibilität).
                    Wie soll ich das denn interpretieren?

                    Beispiele:

                    Warning: Mixing Pointers to signed and unsigned char  (mir doch egal, ich mach doch keine Arithmetik damit!)

                    DWORD n;
                      if (n==-1)
                       { ... }
                    Warning: Constant out of range in comparison  (Scheißcompiler! Du sollst nicht denken, sondern machen!)

                    BYTE  *b;
                    DWORD *d;
                      d = b;
                    Error: Type mismatch  (Herrje! Pointer ist pointer! Was ich damit mache, ist doch mein Problem!)

                    Noch mehr Beispiele?

                    Naja, da gibt es ja schon einen größeren Unterschied zwischen Assembler und C, vor allem zu C++. Am besten ist es, die Denkweisen und Paradigmen, die man von der einen Programmiersprache kennt, vollkommen über Bord zu werfen und sich in die Sprache einzudenken, mit der man gerade arbeitet.

                    Nein, das kann ich nicht. Für mich ist Assembler die Königin aller Programmiersprachen (denn nur da habe ich _wirklich_ alles selbst in der Hand), und alles andere muss sich bei mir daran messen. Da kommt C zwar schon recht gut ran, aber manchmal eben nicht nah genug.

                    Das kann ich nicht bestätigen. Ich kann mittlerweile recht gut C++-Programmieren und ich finde, dass gerade die OOP (in C++) zusammen mit der STL gute Helfer bei der Vermeidung unnötiger Sicherheitslücken, Speicherlecks, … sind.

                    Ja, aber gerade OOP neigt auch dazu, riesige Mengen Maschinencode zu produzieren, obwohl man das gleiche in klassischer prozeduraler Programmierung mit einem Bruchteil an Code hätte realisieren können.
                    Dazu kommt, dass meiner Ansicht nach gerade durch die Kapselung bei der OOP der Überblick über die Zusammenhänge verlorengeht - ist jedenfalls mein persönlicher Eindruck.

                    Was ich z.B. zur Stringbehandlung sagte, gilt auch für dynamisch veränderliche Datenstrukturen: Das alles ist mit C++ deutlich sauberer, unkomplizierter und sicherer machbar.

                    Hmmm. Mir ist deutlich wohler, wenn ich Sachen wie die Speicherverwaltung den dafür zuständigen Betriebssystemfunktionen überlasse, anstatt irgendwelche C++-Konstruktionen zu verwenden, bei denen kaum jemand wirklich im Detail erklären kann, wie sie funktionieren.
                    Und was die Schlampigkeit bei C++ angeht: Der Punkt, der mich am meisten stört, wenn ich fremden Code lesen darf, ist das Deklarieren von neuen Variablen mitten im Programmcode. Reines C zwingt mich wenigstens noch dazu, alle Deklarationen am Anfang eines Blocks vorzunehmen, anstatt Kraut-und-Rüben-artig überall da, wo es mir gerade gefällt.

                    Wobei man in C durchaus sehr sauberen und übersichtlichen Programmcode schreiben kann, wenn man sich ein wenig am Riemen reißt.
                    Selbstverständlich! Es kommt halt stark auf die verwendete Einführung in C an: Ich habe die Sprache damals mit einem Buch gelernt, indem der Autor ständig auf der Problematik mit Arrays, Strings und Pointern eindringlich eingegangen ist („dann ist das Verhalten der Funktion undefiniert“, …). Das hat mich ganz gut „erzogen“.

                    Sehr gut. Dann entwickelt man auch mit der Zeit ein Feeling für sauberen Programmcode. Leider trifft das nicht auf viele Programmierer zu.

                    while ((dp = readdir(dirp)) != NULL)
                        /* write out the files in this directory */
                        printf(dp->d_name);

                      
                    Auaaa!  
                      
                    
                    > Das ganze wird natürlich bei %n im Dateinamen spaßig.  
                      
                    Hä? Das wird bei fast allen Kombinationen mit '%' spaßig. Aber wofür steht %n?  
                      
                    Schönen Abend noch,  
                      
                     Martin  
                    
                    -- 
                    Die Zeit, die man zur Fertigstellung eines Projekts wirklich braucht, ist immer mindestens doppelt so lang wie geplant.  
                    Wurde dieser Umstand bei der Planung bereits berücksichtigt, gilt das Prinzip der Rekursion.  
                      
                    [Schon Urlaubspläne?](http://lemmer-nl.privat.t-online.de)
                    
                    1. Hi Martin!

                      OK, gebongt – float- und double-Werte sind insofern sogar recht praktisch, weil ich da in gewissen Grenzen den Platzverbrauch selbst vorgeben kann. Aber: Wieviele Stellen muss ich denn schlimmstenfalls für einen 64-Bit-Wert vorsehen ...

                      Moment... 2^32 ist ungefähr 4E+09, 2^64 also rund 16E+18, normalisiert 1.6E+19 oder ±8E+18, also schlimmstenfalls 20 Stellen.

                      bzw. welcher Programmierer weiß so etwas?

                      Jeder, der sich nicht mehr "Anfänger" nennen muss. ;-)

                      Genau da haben wir in den meisten Fällen leider das Problem.

                      [...] in anderen Fällen gibt es strlen()
                      Leider fehlte dies im angesprochenen Beispiel. Ich weiß aus eigener Erfahrung, dass man sich auch in C mit dem Prinzip Hoffnung oft durchmogeln kann

                      Ja, gesundes Gottvertrauen (oder Gelassenheit durch Unwissenheit) ist auch eine Methode, und wie du schon andeutest, treten solche Fehler nur in einem Bruchteil der Fälle wirklich gravierend zutage. Aber mir wäre nicht wohl dabei...

                      Das sollte nicht nur dir und mir so gehen, sondern jedem Programmierer. Dann würde zwar der heise-security-Newsticker einschlafen, aber die Anwender könnten ruhiger schlafen und müssten nicht ständig Patches einspielen oder hoffen, dass kein Hacker die aktuelle Lücke ausnutzt.

                      oder die Möglichkeit, %s mit einer Längenangabe zu versehen.
                      Zu welchem Standard ist dann denn kompatibel?

                      Standard? Keine Ahnung, frag mich nicht solche Sachen. Mein Compiler (bzw. seine RTL) versteht das jedenfalls und setzt es korrekt um. Und darauf kommt es letzten Endes an.

                      Darauf kommt es _dir_ letzten Endes an. Ich denke da anders, weil meine Programme sehr häufig auf einer anderen Plattform entwickelt werden, als sie später laufen werden. Dank des GCC schreibe ich mittlerweile sogar Code auf dem Mac und kompiliere die .exe für den Kunden auf meiner alten DOSe. Mit so einer Kompatibilität erspare ich mir auch die Scherereien mit den WinAPI-Änderungen neuer Windows-Versionen oder falls der Kunde auf ein anderes System wechselt.

                      Hmm. Ich bin da wohl aus anderem Holz geschnitzt. Ich liebe die Freiheit, die C mir bietet, auch wenn sie gewisse Risiken birgt.
                      Die muss man erst einmal erblicken und dann unter Kontrolle bekommen.

                      Die Freiheit oder die Risiken?

                      Man muss die Risiken erkennen können und dann eine Möglichkeit sehen, diese unter Kontrolle zu bekommen. Oder anders ausgedrückt: Man muss lernen, mit seiner Freiheit umzugehen.

                      Wie gesagt, die Freiheit weiß ich zu schätzen, und der Risiken bin ich mir größtenteils bewusst, weil ich maschinennah denke und intuitiv den zu meiner C-Anweisung gehörenden Assembler-Code vor Augen habe.

                      Warum programmierst du dann in C und nicht in Assembler?

                      Oft geht mir sogar diese Freiheit nicht weit genug, so dass ich mich über Beschränkungen der Sprache an sich oder eines bestimmten Compilers ärgere (Stichwort Typkompatibilität).
                      Wie soll ich das denn interpretieren?

                      Beispiele:

                      Warning: Mixing Pointers to signed and unsigned char (mir doch egal, ich mach doch keine Arithmetik damit!)

                      Und was passiert beim Dereferenzieren? Du vergleichst einen signed mit einem unsigned char, also einen Datentyp mit Wertebereich [-128,127] mit einem Datentyp des Wertebereiches [0,255].

                      DWORD n;
                        if (n==-1)
                         { ... }
                      Warning: Constant out of range in comparison  (Scheißcompiler! Du sollst nicht denken, sondern machen!)

                      Du kannst doch die Warnungen deaktivieren. Diese Meldung ist gut, es gibt Compiler, die behandeln -1 bei einem DWORD als UINT32MAX-1, also eine sehr große Zahl.

                      BYTE  *b;
                      DWORD *d;
                        d = b;
                      Error: Type mismatch  (Herrje! Pointer ist pointer! Was ich damit mache, ist doch mein Problem!)

                      Wieso willst du so etwas machen, abgesehen davon, dass BYTE und DWORD unterschiedliche Größen haben? In diesem Beispiel zeigt d nach der Zuweisung nicht nur auf b, sondern auch noch auf die 3 Byte dahinter. Was willst du damit anfangen?

                      Noch mehr Beispiele?

                      Besser nicht.

                      […] Am besten ist es, die Denkweisen und Paradigmen, die man von der einen Programmiersprache kennt, vollkommen über Bord zu werfen und sich in die Sprache einzudenken, mit der man gerade arbeitet.

                      Nein, das kann ich nicht. Für mich ist Assembler die Königin aller Programmiersprachen (denn nur da habe ich _wirklich_ alles selbst in der Hand), und alles andere muss sich bei mir daran messen. Da kommt C zwar schon recht gut ran, aber manchmal eben nicht nah genug.

                      OK, ich würde Assembler als die Mutter aller Sprachen bezeichnen, weil jeder Compile-Vorgang, jede virtuelle Maschine später bei einer Assembler-Art landet, und natürlich habe ich deshalb alles unter Kontrolle, aber wofür? In den meisten Fällen kann man meiner Meinung nach auf die Hersteller von Betriebssystemen, Bibliotheken und Programmiersprachen vertrauen, dass sie keinen groben Schrott anbieten.
                      Mit diesem Argument würde ich übrigens nie Windows benutzen, weil es viel zu viele Seiteneffekte hat, die man nicht in die Hand nehmen kann. Gentoo dürfte das richtige Linux für dich sein.

                      Das kann ich nicht bestätigen. Ich kann mittlerweile recht gut C++-Programmieren und ich finde, dass gerade die OOP (in C++) zusammen mit der STL gute Helfer bei der Vermeidung unnötiger Sicherheitslücken, Speicherlecks, … sind.

                      Ja, aber gerade OOP neigt auch dazu, riesige Mengen Maschinencode zu produzieren, obwohl man das gleiche in klassischer prozeduraler Programmierung mit einem Bruchteil an Code hätte realisieren können.

                      Soweit ich weiß, wurde OOP auch nicht erfunden, um mit weniger Maschinencode performantere (und buntere) Programme erstellen zu können, sondern aus praktischen Überlegungen wie Wiederverwendbarkeit, Modularisierung, Wartbarkeit, Portabilität.

                      Dazu kommt, dass meiner Ansicht nach gerade durch die Kapselung bei der OOP der Überblick über die Zusammenhänge verlorengeht - ist jedenfalls mein persönlicher Eindruck.

                      Das soll er ja auch in gewisser Weise. Schau dir z.B. mal das Stream-Konzept von C++ an: Unabhängig davon, mit was für einem Ausgabe-„Gerät“ (bzw. Eingabe-) ich es zu tun habe (Dateien, Strings, Pipes), die Schnittstelle ist immer gleich; außerdem kann man auf diesem Konzept aufbauend weitere Klassen hinzudefinieren, die analog funktionieren, z.B. Sockets, Datenbanken oder XML-Dokumente. Der Vorteil ist eine konsistente API, in der es vollkommen gleichgültig ist, woher meine Daten kommen und wohin sie wandern. Wenn ich in meinem Programm später auf ein anderes „Gerät“ umsteige, brauche ich nur wenige Code-Zeilen zu ändern.

                      Was ich z.B. zur Stringbehandlung sagte, gilt auch für dynamisch veränderliche Datenstrukturen: Das alles ist mit C++ deutlich sauberer, unkomplizierter und sicherer machbar.

                      Hmmm. Mir ist deutlich wohler, wenn ich Sachen wie die Speicherverwaltung den dafür zuständigen Betriebssystemfunktionen überlasse, anstatt irgendwelche C++-Konstruktionen zu verwenden, bei denen kaum jemand wirklich im Detail erklären kann, wie sie funktionieren.

                      Das Rad wird auch mit C++ keiner neu erfunden haben, von daher kannst du davon ausgehen, dass auch die C++-Allokatoren malloc und Co verwenden werden. Außerdem sind mit den Techniken von C++ Optimierungen in der Speicherverwaltung möglich, die man in C selbst nie entwickeln würde, weil es einfach viel zu viel Aufwand wäre.

                      Und was die Schlampigkeit bei C++ angeht: Der Punkt, der mich am meisten stört, wenn ich fremden Code lesen darf, ist das Deklarieren von neuen Variablen mitten im Programmcode. Reines C zwingt mich wenigstens noch dazu, alle Deklarationen am Anfang eines Blocks vorzunehmen, anstatt Kraut-und-Rüben-artig überall da, wo es mir gerade gefällt.

                      Der Vorteil daran, dass alles eine Anweisung ist, taucht z.B. dann auf, wenn du mit großen Objekten arbeitest, von denen du erst innerhalb der Funktion (also nicht schon Anfang) weißt, ob du sie brauchst oder nicht. Aber wie auch sonst kannst du nicht das schlampige Kodieren hauptsächlich der Programmiersprache anlasten. Mit Assembler kann man wahrscheinlich eher nen Obfuscated-…-Contest gewinnen als mit C.

                      while ((dp = readdir(dirp)) != NULL)
                          /* write out the files in this directory */
                          printf(dp->d_name);

                      
                      >   
                      > Auaaa!  
                      >   
                      > > Das ganze wird natürlich bei %n im Dateinamen spaßig.  
                      >   
                      > Hä? Das wird bei fast allen Kombinationen mit '%' spaßig. Aber wofür steht %n?  
                        
                      Naja, mit sämtlichen %-Kombinationen gibt es nur einen harmlosen Speicherzugriffsfehler. Mit %n kannst du in die korrespondierende Integervariable schreiben, wieviele Elemente printf bislang bearbeitet hat:  
                        
                      ~~~c
                        
                      char *name;  
                      int elem;  
                        
                      printf("Hallo %s, %lu Sekunden seit 1.1.1970\n%n", name, time(NULL), &elem);  
                        
                      /* elem enthält nun den Wert 2. */  
                      
                      

                      D.h. mit %n schreibst du auf dem Stack! Bei dem schicken Speicherlayout der Intel-CPUs bzw. diverser Betriebssysteme ist damit (fast) alles möglich, z.B. Code zur Ausführung vorlegen oder Rücksprungadressen umbiegen.

                      Viele Grüße,
                      Robert

                      1. moin Robert,

                        Wie gesagt, die Freiheit weiß ich zu schätzen, und der Risiken bin ich mir größtenteils bewusst, weil ich maschinennah denke und intuitiv den zu meiner C-Anweisung gehörenden Assembler-Code vor Augen habe.
                        Warum programmierst du dann in C und nicht in Assembler?

                        *seufz*  das frage ich mich auch immer wieder...

                        Warning: Mixing Pointers to signed and unsigned char (mir doch egal, ich mach doch keine Arithmetik damit!)

                        Und was passiert beim Dereferenzieren? Du vergleichst einen signed mit einem unsigned char, also einen Datentyp mit Wertebereich [-128,127] mit einem Datentyp des Wertebereiches [0,255].

                        Ja und? Deswegen sagte ich doch, ich betreibe keine Arithmetik damit, sondern verwende char (meistens) nur als Zeichen. Da ist es mir doch wurscht, ob signed oder unsigned.

                        DWORD n;
                          if (n==-1)
                           { ... }
                        Warning: Constant out of range in comparison  (Scheißcompiler! Du sollst nicht denken, sondern machen!)

                        Du kannst doch die Warnungen deaktivieren. Diese Meldung ist gut, es gibt Compiler, die behandeln -1 bei einem DWORD als UINT32MAX-1, also eine sehr große Zahl.

                        Völlig schnurz. Wenn die CPU irgendwann über den Code herfällt, ist -1 genau dasselbe wie 0xFFFFFFFF, nur handlicher geschrieben.

                        BYTE  *b;
                        DWORD *d;
                          d = b;
                        Error: Type mismatch  (Herrje! Pointer ist pointer! Was ich damit mache, ist doch mein Problem!)

                        Wieso willst du so etwas machen, abgesehen davon, dass BYTE und DWORD unterschiedliche Größen haben? In diesem Beispiel zeigt d nach der Zuweisung nicht nur auf b, sondern auch noch auf die 3 Byte dahinter.

                        Das ist doch gerade das Schöne! Z.B. wenn ich -je nach Programmkontext- in bestimmten Speicherbereichen mal byteweise, mal doppelwortweise organisierte Daten habe.

                        OK, ich würde Assembler als die Mutter aller Sprachen bezeichnen, weil jeder Compile-Vorgang, jede virtuelle Maschine später bei einer Assembler-Art landet, und natürlich habe ich deshalb alles unter Kontrolle, aber wofür? In den meisten Fällen kann man meiner Meinung nach auf die Hersteller von Betriebssystemen, Bibliotheken und Programmiersprachen vertrauen, dass sie keinen groben Schrott anbieten.

                        Nein, das nicht. Aber gerade die "Hersteller" von vorgefertigten Standardbibliotheken packen meist jede Menge tolle Flexibilität in ihre Funktionen, von der ich in einer bestimmten Anwendung vielleicht, wenn's viel ist, 10% ausnutze. Den Programmcode für den Rest schleppt meine Applikation nachher als Ballast mit.

                        Mit diesem Argument würde ich übrigens nie Windows benutzen, weil es viel zu viele Seiteneffekte hat, die man nicht in die Hand nehmen kann. Gentoo dürfte das richtige Linux für dich sein.

                        Zu dieser Erkenntnis bin ich auch schon gekommen, und das werde ich demnächst -vielleicht im Weihnachtsurlaub, wenn ich mal wieder ein paar Tage Zeit habe- einmal angehen. ;-)

                        Soweit ich weiß, wurde OOP auch nicht erfunden, um mit weniger Maschinencode performantere (und buntere) Programme erstellen zu können, sondern aus praktischen Überlegungen wie Wiederverwendbarkeit, Modularisierung, Wartbarkeit, Portabilität.

                        Hm, ja - Punkt für dich. Aber dann nehme ich die Modularisierung und Dokumentation zugunsten höherer Effizienz doch lieber selbst in die Hand.

                        Dazu kommt, dass meiner Ansicht nach gerade durch die Kapselung bei der OOP der Überblick über die Zusammenhänge verlorengeht - ist jedenfalls mein persönlicher Eindruck.
                        Das soll er ja auch in gewisser Weise.

                        Ja, und das ist das Problem, wenn man mal fremde C++-Programme bekommt und erweitern oder anpassen möchte. Dann verbringt man Stunden und Tage damit, die Zusammenhänge zwischen den zahlreichen Klassen zu analysieren, um dann irgendwann festzustellen, dass die Struktur schon zu verfilzt ist, um die gewünschte Änderung mit vertretbarem Aufwand noch realisieren zu können, und dass man günstiger wegkommt, wenn man das Programm (oder zumindest Teile davon) von Grund auf neu aufsetzt.

                        Schau dir z.B. mal das Stream-Konzept von C++ an: Unabhängig davon, mit was für einem Ausgabe-„Gerät“ [...] später auf ein anderes „Gerät“ umsteige, brauche ich nur wenige Code-Zeilen zu ändern.

                        Das kann ich bei klassischer prozeduraler Programmierung aber auch, wenn ich die Aufrufschnittstellen meiner Funktionen sinnvoll festgelegt habe.

                        Aber wie auch sonst kannst du nicht das schlampige Kodieren hauptsächlich der Programmiersprache anlasten.

                        Vielleicht nicht hauptsächlich. Aber wenn sie es noch begünstigt, oder sogar in Musterlösungen propagiert, finde ich das nicht wirklich okay.

                        Mit Assembler kann man wahrscheinlich eher nen Obfuscated-…-Contest gewinnen als mit C.

                        Zweifellos. Andererseits ist Assembler-Code oft leichter nachvollziehbar, weil er schon sequentialisiert ist und nicht unzählige verschachtelte Ausdrücke enthält. Der Aufwand, solche Strukturen aufzudröseln, liegt hier beim Programmierer selbst und nicht beim Compiler.

                        Mit %n kannst du in die korrespondierende Integervariable schreiben, wieviele Elemente printf bislang bearbeitet hat:

                        Du liebe Güte - wo ist das denn her? Das habe ich hier auch zum ersten Mal gelesen. Abgesehen davon ist mir absolut unklar, wozu das gut sein soll.

                        D.h. mit %n schreibst du auf dem Stack! Bei dem schicken Speicherlayout der Intel-CPUs bzw. diverser Betriebssysteme ist damit (fast) alles möglich, z.B. Code zur Ausführung vorlegen oder Rücksprungadressen umbiegen.

                        Ja, da hast du natürlich Recht. Aber wer implementiert auch solche kranken Funktionen. Boah...

                        In diesem Sinne noch einen schönen Regentag,

                        Martin

                        --
                        Wer schläft, sündigt nicht.
                        Wer vorher sündigt, schläft besser.
                        Schon Urlaubspläne?
                        1. Hallo Martin!

                          Warning: Mixing Pointers to signed and unsigned char (mir doch egal, ich mach doch keine Arithmetik damit!)

                          Und was passiert beim Dereferenzieren? Du vergleichst einen signed mit einem unsigned char, also einen Datentyp mit Wertebereich [-128,127] mit einem Datentyp des Wertebereiches [0,255].

                          Ja und? Deswegen sagte ich doch, ich betreibe keine Arithmetik damit, sondern verwende char (meistens) nur als Zeichen. Da ist es mir doch wurscht, ob signed oder unsigned.

                          Und warum dann nicht einheitlich char bzw. falls das Vorzeichen relevant ist halt (un)signed char? Diese Fehlermeldung ist übrigens vergleichbar mit folgender, da du Pointer auf unterschiedliche Objekte/Datentypen verwendest:

                          DWORD n;
                            if (n==-1)
                             { ... }
                          Warning: Constant out of range in comparison  (Scheißcompiler! Du sollst nicht denken, sondern machen!)

                          Du kannst doch die Warnungen deaktivieren. Diese Meldung ist gut, es gibt Compiler, die behandeln -1 bei einem DWORD als UINT32MAX-1, also eine sehr große Zahl.

                          Völlig schnurz. Wenn die CPU irgendwann über den Code herfällt, ist -1 genau dasselbe wie 0xFFFFFFFF, nur handlicher geschrieben.

                          Darauf kannst du dich allerdings im Allgemeinen nicht verlassen. Dein Code ist hochgradig plattform-spezifisch. Und wer garantiert dir, dass dein Programm nicht später auf einem Rechner mit einem Betriebssystem läuft, auf dem -1 ungleich 0xFFFFFFFF ist?

                          BYTE  *b;
                          DWORD *d;
                            d = b;
                          Error: Type mismatch  (Herrje! Pointer ist pointer! Was ich damit mache, ist doch mein Problem!)

                          Wieso willst du so etwas machen, abgesehen davon, dass BYTE und DWORD unterschiedliche Größen haben? In diesem Beispiel zeigt d nach der Zuweisung nicht nur auf b, sondern auch noch auf die 3 Byte dahinter.

                          Das ist doch gerade das Schöne! Z.B. wenn ich -je nach Programmkontext- in bestimmten Speicherbereichen mal byteweise, mal doppelwortweise organisierte Daten habe.

                          Das kann man machen, du weißt aber schon, dass es auf 32-Bit-Computern deutlich schneller ist, auf je 4-Byte zuzugreifen als auf eines. Deshalb ist dort ein bool auch 4-Byte groß. Von bitweisem Datenzugriff ganz zu schweigen. Schreibst du Programme, die viel Arbeitsspeicher allokieren? Ansonsten denke ich, dass eine Geschwindigkeitsoptimierung sinnvoller ist.

                          […] In den meisten Fällen kann man meiner Meinung nach auf die Hersteller von Betriebssystemen, Bibliotheken und Programmiersprachen vertrauen, dass sie keinen groben Schrott anbieten.

                          Nein, das nicht. Aber gerade die "Hersteller" von vorgefertigten Standardbibliotheken packen meist jede Menge tolle Flexibilität in ihre Funktionen, von der ich in einer bestimmten Anwendung vielleicht, wenn's viel ist, 10% ausnutze. Den Programmcode für den Rest schleppt meine Applikation nachher als Ballast mit.

                          Abgesehen von C++, macht sich das während der Laufzeit gravierend bemerkbar? Da gibt es genug andere Faktoren, die nicht nur dein Programm, sondern den kompletten Rechner ausbremsen können. Ich weiß, wenn jeder Programmierer denkt „heutige Rechner sind schnell genug“, hat der Anwender im Endeffekt wieder nichts davon, aber die Verhältnisse müssen meiner Meinung nach stimmen.

                          Im Übrigen finde ich dein Ballast-Argument nachvollziehbar in der Art, dass mir kleine, schlanke Bibliotheken deutlich lieber sind als „Wir haben die Lösung für alles“.

                          Dazu kommt, dass meiner Ansicht nach gerade durch die Kapselung bei der OOP der Überblick über die Zusammenhänge verlorengeht - ist jedenfalls mein persönlicher Eindruck.
                          Das soll er ja auch in gewisser Weise.

                          Ja, und das ist das Problem, wenn man mal fremde C++-Programme bekommt und erweitern oder anpassen möchte. Dann verbringt man Stunden und Tage damit, die Zusammenhänge zwischen den zahlreichen Klassen zu analysieren, um dann irgendwann festzustellen, dass die Struktur schon zu verfilzt ist, um die gewünschte Änderung mit vertretbarem Aufwand noch realisieren zu können, und dass man günstiger wegkommt, wenn man das Programm (oder zumindest Teile davon) von Grund auf neu aufsetzt.

                          Dieses Problem ist aus meiner Sicht nicht C++-spezifisch. Ich kenne C-Programme sowie Bibliotheken oder Teile davon, von denen man glaubt, dass man ihre Funktionalität benutzen könnte und nach langem hin und her feststellt, hätte man gleich das Rad neu erfunden, wäre man jetzt schon weiter.

                          Schau dir z.B. mal das Stream-Konzept von C++ an: Unabhängig davon, mit was für einem Ausgabe-„Gerät“ [...] später auf ein anderes „Gerät“ umsteige, brauche ich nur wenige Code-Zeilen zu ändern.

                          Das kann ich bei klassischer prozeduraler Programmierung aber auch, wenn ich die Aufrufschnittstellen meiner Funktionen sinnvoll festgelegt habe.

                          Da hast du vollkommen Recht. Aber sobald ich anfange, bestimmte Informationen an das letzlich verwendete „Subsystem“ bei jedem Funktionsaufruf mitschleppen zu müssen (File- oder Socket-Handles, Datenbank-Kennungen, …), wird für mich die ganze Sache lästig, weil dieser prozedurale Code objekt-orientiert ist, aber die Objekte und Methoden kompliziert umschrieben werden. Das kann man einfacher und eleganter mit echter OOP lösen.

                          Aber wie auch sonst kannst du nicht das schlampige Kodieren hauptsächlich der Programmiersprache anlasten.

                          Vielleicht nicht hauptsächlich. Aber wenn sie es noch begünstigt, oder sogar in Musterlösungen propagiert, finde ich das nicht wirklich okay.

                          Schau dir mal PHP an, das ist in meinen Augen an Verleitung zur Schlampigkeit nicht zu überbieten. Und es ist schon ein Unterschied, ob ein kleines Tool nur bei Vollmond zur Sommersonnenwende eine Lücke offenbart oder ob ein Webserver offen steht.
                          Außerdem denke ich, dass mit den neueren Sprachkonzepten in C++ wie z.B. Templates oder dem „Erzwingen“ expliziter Typecasts ein großer Schritt in Richtung sauberen Programmierens gegangen worden ist. Man kann natürlich nicht von jedem C++-Programmierer erwarten, dass er sich den Stroustrup ins Haus holt, aber besser wäre es. Der gute Mann – seines Zeichens Erfinder von C++ – schreibt sehr viel und eindringlich über sauberen, wiederverwendbaren Code.

                          Mit %n kannst du in die korrespondierende Integervariable schreiben, wieviele Elemente printf bislang bearbeitet hat:

                          Du liebe Güte - wo ist das denn her?

                          Aus der Dokumentation der printf()-Familie.

                          Das habe ich hier auch zum ersten Mal gelesen. Abgesehen davon ist mir absolut unklar, wozu das gut sein soll.

                          Vielleicht als Backdoor ;-)

                          Viele Grüße,
                          Robert

                          1. n'Abend!

                            Ja und? Deswegen sagte ich doch, ich betreibe keine Arithmetik damit, sondern verwende char (meistens) nur als Zeichen. Da ist es mir doch wurscht, ob signed oder unsigned.
                            Und warum dann nicht einheitlich char bzw. falls das Vorzeichen relevant ist halt (un)signed char?

                            weil die Argumente von Funktionen, die ich nutzen möchte, teils sehr unterschiedlich deklariert sind, je nachdem, woher sie stammen. Mal als char, mal als uchar, mal als BYTE, mal als INT8, und letztendlich meinen sie alle dasselbe: Eine Einheit von 8 Bits, die ein Zeichen repräsentieren.

                            Völlig schnurz. Wenn die CPU irgendwann über den Code herfällt, ist -1 genau dasselbe wie 0xFFFFFFFF, nur handlicher geschrieben.
                            Darauf kannst du dich allerdings im Allgemeinen nicht verlassen. Dein Code ist hochgradig plattform-spezifisch.

                            Ja und? Wenn ich eine bestimmte Software schreibe, dann schreibe ich auch für eine bestimmte Plattform bzw. Systemumgebung. Also gehe ich auch auf die Gegebenheiten eben dieser Systemumgebung ein. Wenn eine andere Rechnerarchitektur bzw. ein anderes Betriebssystem ausnahmsweise negative Zahlen *nicht* durchs Zweierkomplement darstellt, muss ich das eben anders schreiben.

                            Und wer garantiert dir, dass dein Programm nicht später auf einem Rechner mit einem Betriebssystem läuft, auf dem -1 ungleich 0xFFFFFFFF ist?

                            Zunächst garantiere *ich* das, indem ich sage: Dieser Programmcode ist für Win32 geschrieben. Oder für DOS. Oder für 8051 µCs.

                            Das kann man machen, du weißt aber schon, dass es auf 32-Bit-Computern deutlich schneller ist, auf je 4-Byte zuzugreifen als auf eines.

                            Das ist nicht richtig. Zumindest bei x86-CPUs braucht ein BYTE-Zugriff exakt genausoviele Taktzyklen wie ein DWORD-Zugriff. Im Gegenteil: Ein DWORD-Zugriff kann sogar länger dauern, dann nämlich, wenn die Adresse nicht durch 4 teilbar ist. Es gibt also keine Rechtfertigung, byteweise strukturierte Daten auf DWORD aufzublähen und dadurch das Vierfache an Speicher zu verschwenden wie eigentlich nötig.

                            Schreibst du Programme, die viel Arbeitsspeicher allokieren?

                            Ja, gelegentlich. Aktuell bin ich dabei, eine vor 2 Jahren begonnene Win32-Applikation auszubauen, die je nach Konfiguration leicht und locker mal 50..100MB RAM belegt. Da ist Speicherökonomie durchaus ein Thema.

                            Ansonsten denke ich, dass eine Geschwindigkeitsoptimierung sinnvoller ist.

                            ACK. Aber das, was du vorschlägst, ist keine Geschwindigkeitsoptimierung.

                            Den Programmcode für den Rest schleppt meine Applikation nachher als Ballast mit.
                            Abgesehen von C++, macht sich das während der Laufzeit gravierend bemerkbar?

                            Nein, sicher nicht. Aber ich finde es nicht erstrebenswert, den Ressourcenhunger eines Programms (Plattenplatz und Arbeitsspeicher) unnötig in die Höhe zu treiben.

                            Ich weiß, wenn jeder Programmierer denkt „heutige Rechner sind schnell genug“, hat der Anwender im Endeffekt wieder nichts davon, aber die Verhältnisse müssen meiner Meinung nach stimmen.

                            Was für Verhältnisse? Das Problem, das du ansprichst, ist mir durchaus geläufig. Ich habe es bisher immer "elektronische Inflation" genannt: Die Programmierer gehen verschwenderisch mit den Ressourcen um, weil sie ja zur Verfügung stehen, und die Rechnerhersteller sehen den Bedarf für immer mehr Speicher und Rechenleistung, weil aktuelle Applikationen aufgrund der Faulheit der Programmierer die Maschinen bis an die Grenze belasten. Ich würde es begrüßen, wenn sich wieder mehr Programmierer dieses Dilemmas bewusst würden.

                            Im Übrigen finde ich dein Ballast-Argument nachvollziehbar in der Art, dass mir kleine, schlanke Bibliotheken deutlich lieber sind als „Wir haben die Lösung für alles“.

                            Naja, wenigstens da sind wir uns einig. ;-)

                            [...] und dass man günstiger wegkommt, wenn man das Programm (oder zumindest Teile davon) von Grund auf neu aufsetzt.
                            Dieses Problem ist aus meiner Sicht nicht C++-spezifisch. Ich kenne C-Programme sowie Bibliotheken oder Teile davon, von denen man glaubt, dass man ihre Funktionalität benutzen könnte und nach langem hin und her feststellt, hätte man gleich das Rad neu erfunden, wäre man jetzt schon weiter.

                            Naja, mir sind solche Sachen bei C++ am häufigsten aufgefallen. Deshalb nehme ich, wenn ich Libs für bestimmte Zwecke suche, auch bevorzugt Plain C.

                            Da hast du vollkommen Recht. Aber sobald ich anfange, bestimmte Informationen an das letzlich verwendete „Subsystem“ bei jedem Funktionsaufruf mitschleppen zu müssen (File- oder Socket-Handles, Datenbank-Kennungen, …), wird für mich die ganze Sache lästig, weil dieser prozedurale Code objekt-orientiert ist, aber die Objekte und Methoden kompliziert umschrieben werden. Das kann man einfacher und eleganter mit echter OOP lösen.

                            Für meinen Geschmack ist es eben *nicht* einfacher und eleganter, weil wichtige Mechanismen automatisiert und dadurch verschleiert werden. Ich will aber sehen, was da abläuft!

                            Vielleicht nicht hauptsächlich. Aber wenn sie es noch begünstigt, oder sogar in Musterlösungen propagiert, finde ich das nicht wirklich okay.
                            Schau dir mal PHP an, das ist in meinen Augen an Verleitung zur Schlampigkeit nicht zu überbieten.

                            Kann ich nicht abstreiten. ;-)

                            Gute Nacht erstmal,

                            Martin

                            --
                            Die beste Informationsquelle sind Leute, die jemand anderem versprochen haben, nichts weiterzuerzählen.
                              (alte Journalistenweisheit)
                            Schon Urlaubspläne?
                            1. Moin Martin!

                              Das kann man machen, du weißt aber schon, dass es auf 32-Bit-Computern deutlich schneller ist, auf je 4-Byte zuzugreifen als auf eines.

                              Das ist nicht richtig. Zumindest bei x86-CPUs braucht ein BYTE-Zugriff exakt genausoviele Taktzyklen wie ein DWORD-Zugriff.

                              Wie denn das? Fahren da nicht bei einem Befehl immer 32 Bit Daten mit dem Bus?

                              Im Gegenteil: Ein DWORD-Zugriff kann sogar länger dauern, dann nämlich, wenn die Adresse nicht durch 4 teilbar ist.

                              Sollten „intelligente“ Compiler™ (bzw. Speicher-Allokatoren) nicht automatisch die Daten dem entsprechend zur Verfügung stellen?

                              Es gibt also keine Rechtfertigung, byteweise strukturierte Daten auf DWORD aufzublähen und dadurch das Vierfache an Speicher zu verschwenden wie eigentlich nötig.

                              In wie fern macht sich das denn bemerkbar, wer benutzt also schon genug DWORDs (in ISO C99 heißt das uint32_t) anstelle von BYTEs (aka. uint8_t)?

                              Zu deinem Problem an dieser Stelle: Warum nimmst du keine union:

                                
                              typedef union {  
                                  BYTE b;  
                                  DWORD d;  
                              } dword_byteweise;  
                                
                              dword_byteweise db;  
                                
                              /* Mit db.b = … kannst du nun ein BYTE speichern und mit db.d als  
                               * DWORD wieder auslesen.  
                               */  
                              
                              

                              Ansonsten denke ich, dass eine Geschwindigkeitsoptimierung sinnvoller ist.

                              ACK. Aber das, was du vorschlägst, ist keine Geschwindigkeitsoptimierung.

                              OK, mit DOSen kenne ich mich nicht so aus. Die Aussage, das Programme signifikant schneller wurden, als man bool in einen int der für die Plattform typische Größe zu packen (d.h. auf 32-Bittern steht irgendwo typedef int bool), stammt nicht von mir, sondern aus dem Buch von Stroustrup.

                              Ich weiß, wenn jeder Programmierer denkt „heutige Rechner sind schnell genug“, hat der Anwender im Endeffekt wieder nichts davon, aber die Verhältnisse müssen meiner Meinung nach stimmen.

                              Was für Verhältnisse?

                              Damit meine ich fragwürdige Optimierungen, die mir 5 Byte Hauptspeicher (siehe auch oben) und zweihundert Taktzyklen (so schnell kann man noch nicht mal blinzeln) sparen.

                              Das Problem, das du ansprichst, ist mir durchaus geläufig. Ich habe es bisher immer "elektronische Inflation" genannt: Die Programmierer gehen verschwenderisch mit den Ressourcen um, weil sie ja zur Verfügung stehen, und die Rechnerhersteller sehen den Bedarf für immer mehr Speicher und Rechenleistung, weil aktuelle Applikationen aufgrund der Faulheit der Programmierer die Maschinen bis an die Grenze belasten. Ich würde es begrüßen, wenn sich wieder mehr Programmierer dieses Dilemmas bewusst würden.

                              Wieso denn? Inflation ist doch eine praktische Sache, auch in der Volkswirtschaft, weil es dem Kunden schmackhaft gemacht wird, seine wertloser werdenden Güter/Computer durch neuere zu ersetzen, d.h. sparen ist uncool. Wenn die Programmierer verantwortlich mit den Rechnerressourcen umgingen, gäbe es nicht ca. alle drei Jahre das Bedürfnis nach einem neuen, leistungsfähigeren Computer. Und die Programmierer freuen sich darauf, dass sie wieder mehr Speicher, mehr CPU-Zeit (und mehr Farben) zum Ausfüllen haben. Das ganze ist ein toller Kreislauf für alle, die mit Computern Geld verdienen.

                              Viele Grüße,
                              Robert

                              1. Hi Robert,

                                Das ist nicht richtig. Zumindest bei x86-CPUs braucht ein BYTE-Zugriff exakt genausoviele Taktzyklen wie ein DWORD-Zugriff.
                                Wie denn das? Fahren da nicht bei einem Befehl immer 32 Bit Daten mit dem Bus?

                                Richtig. Und bei einem WORD-Zugriff werden 16, bei einem BYTE-Zugriff sogar 24 davon ignoriert. Der Zeitbedarf bleibt der gleiche.

                                Im Gegenteil: Ein DWORD-Zugriff kann sogar länger dauern, dann nämlich, wenn die Adresse nicht durch 4 teilbar ist.
                                Sollten „intelligente“ Compiler™ (bzw. Speicher-Allokatoren) nicht automatisch die Daten dem entsprechend zur Verfügung stellen?

                                Ja, wenn man sie mit entsprechenden Direktiven oder Grundeinstellungen nett darum bittet.

                                Zu deinem Problem an dieser Stelle: Warum nimmst du keine union:

                                Das ist ja nicht Sinn der Sache. Eine union nimmt soviel Speicherplatz in Anspruch wie ihr größtes Element. Wo bleibt also der Nutzen, wenn ich so einen Datentyp wieder in ein struct oder Array stecken will? Ich will ja z.B. einen gegebenen Speicherbereich mit Datenstrukturen füllen (BYTE und DWORD waren nur willkürlich gewählte, einfache Beispiele, meist sind es structs), deren genauer Aufbau erst zur Laufzeit durch Konfigurationsdateien oder Benutzerangaben bekannt wird.

                                Was für Verhältnisse?
                                Damit meine ich fragwürdige Optimierungen, die mir 5 Byte Hauptspeicher (siehe auch oben) und zweihundert Taktzyklen (so schnell kann man noch nicht mal blinzeln) sparen.

                                Im Einzelfall gebe ich dir Recht. Aber bei großen Arrays sind auch 3 Byte Einsparung pro Element nicht zu verachten; bei Schleifen, die viele tausend Mal durchlaufen werden, sind auch 200 Taktzyklen schon interessant. Vor allem (aber nicht nur) dann, wenn man zur Abwechslung mal nicht für einen 3GHz-Boliden schreibt, sondern für einen niedlichen kleinen 8bit-µC.
                                Außerdem ist es ein gutes Gefühl, wenn die Kollegen anerkennend fragen, wie ich den so viel Funktionalität in einem gerade mal 200kB großen Executable unterbringe, oder warum andere, kommerzielle Produkte nicht genauso schnell sein können. :-)

                                Wieso denn? Inflation ist doch eine praktische Sache, auch in der Volkswirtschaft, weil es dem Kunden schmackhaft gemacht wird, seine wertloser werdenden Güter/Computer durch neuere zu ersetzen, d.h. sparen ist uncool. Wenn die Programmierer verantwortlich mit den Rechnerressourcen umgingen, gäbe es nicht ca. alle drei Jahre das Bedürfnis nach einem neuen, leistungsfähigeren Computer. Und die Programmierer freuen sich darauf, dass sie wieder mehr Speicher, mehr CPU-Zeit (und mehr Farben) zum Ausfüllen haben. Das ganze ist ein toller Kreislauf für alle, die mit Computern Geld verdienen.

                                Ja. Und ein Fluch für alle, die einen Computer, das nötige Zubehör und die Software einfach nur brauchen. Ich kenne genug Leute, die noch heute einen Rechner und Software benutzen, die fünf Jahre und älter sind, weil es den eigenen Anforderungen genügt. Auch wenn uns die Werbung suggeriert, dass man alle paar Monate einen neuen PC haben müsste.

                                Schönes Wochenende,

                                Martin

                                --
                                Ich wollt', ich wär ein Teppich. Dann könnte ich morgens liegenbleiben.
                        2. 你好 Martin,

                          Völlig schnurz. Wenn die CPU irgendwann über den Code herfällt, ist -1
                          genau dasselbe wie 0xFFFFFFFF, nur handlicher geschrieben.

                          Negative Zahlen werden nicht immer im Zweierkomplement abgebildet. Aus dem
                          Standard:

                          6.2.6.2 Integer types
                             2 [...]
                               If the sign bit is one, the value shall be modified in one of the
                               following ways:
                               — the corresponding value with sign bit 0 is negated (sign and
                                 magnitude);
                               — the sign bit has the value -(2N) (two’s complement);
                               — the sign bit has the value -(2N - 1) (one’s complement).

                          Das heisst, der Compiler hat die Möglichkeit, zwischen drei Darstellungen
                          zu wählen. Dein Code ist also in höchstem Maße Compiler-spezifisch.

                          OK, ich würde Assembler als die Mutter aller Sprachen bezeichnen, weil
                          jeder Compile-Vorgang, jede virtuelle Maschine später bei einer
                          Assembler-Art landet, [...]

                          Nö, du, ich habe schon VMs gesehen, die nur mit Syntax-Bäumen arbeiten und
                          den Schritt zum Assembler nicht machen.

                          Mit %n kannst du in die korrespondierende Integervariable schreiben,
                          wieviele Elemente printf bislang bearbeitet hat:

                          Das stimmt nicht: %n schreibt die Anzahl der geschriebenen Chars in die
                          Variable. Nicht die Anzahl der Elemente, die bearbeitet wurden.

                          Du liebe Güte - wo ist das denn her? Das habe ich hier auch zum ersten
                          Mal gelesen. Abgesehen davon ist mir absolut unklar, wozu das gut sein
                          soll.

                          printf() kann die Verarbeitung abbrechen - etwa, wenn in den Output-Stream
                          nicht mehr geschrieben werden kann, wegen eines vollen Send-Buffers oder so
                          (gibt dann ein EAGAIN). Eignet sich also z. B. um festzustellen, an welcher
                          Stelle man den Funktions-Aufruf fortsetzen muss.

                          D.h. mit %n schreibst du auf dem Stack!

                          Nein: kannst du auf den Stack schreiben. Man muss nicht. Nichts hindert
                          einen daran, die Variable auf dem Heap anzulegen :)

                          再见,
                           克里斯蒂安

                          --
                          Block-Installation Nr. 5 | Renovation der Mensa-Nord
                          Q: God, root, what's the difference?
                          A: God is merciful.
                          http://wwwtech.de/
                          1. Hi 克里斯蒂安!

                            Mit %n kannst du in die korrespondierende Integervariable schreiben, wieviele Elemente printf bislang bearbeitet hat:

                            Das stimmt nicht: %n schreibt die Anzahl der geschriebenen Chars in die Variable. Nicht die Anzahl der Elemente, die bearbeitet wurden.

                            Hast Recht, Lesen bildet (hab grad nochmal in man 3 printf nachgeschaut) bzw. kaum schaut man richtig, steht es da ;-)

                            Viele Grüße,
                            Robert

                          2. Hallo,

                            Das heisst, der Compiler hat die Möglichkeit, zwischen drei Darstellungen
                            zu wählen. Dein Code ist also in höchstem Maße Compiler-spezifisch.

                            nein, deine Schlussfolgerung ist so nicht ganz richtig. Der Compiler muss die Konvention umsetzen, die das jeweilige Zielsystem verwendet. Er hat also nicht die Möglichkeit zu wählen. Insofern ist mein Code nicht compilerspezifisch, aber natürlich plattformspezifisch. Und das finde ich vollkommen richtig.

                            Das stimmt nicht: %n schreibt die Anzahl der geschriebenen Chars in die
                            Variable. Nicht die Anzahl der Elemente, die bearbeitet wurden.

                            Ah, gut - dann ergibt es schon ein bisschen mehr Sinn. Obwohl...

                            [...] um festzustellen, an welcher Stelle man den Funktions-Aufruf fortsetzen muss.

                            Genau dafür geben die printf()-Funktionen doch die Anzahl der geschriebenen Zeichen als Funktionsergebnis zurück. Bestens vertraut sind mir deshalb Konstruktionen wie etwa

                            CHAR *str;
                             [...]
                            str += sprintf("Pattern Line 1", var1, var2);
                            str += sprintf("Pattern Line 2", var3, var4);
                            str += sprintf("Pattern Line 3", var5, var6);
                             ...

                            Gute Nacht erstmal,

                            Martin

                            --
                            Computer lösen für uns Probleme, die wir ohne sie gar nicht hätten.
                            1. 你好 Der,

                              Das heisst, der Compiler hat die Möglichkeit, zwischen drei
                              Darstellungen zu wählen. Dein Code ist also in höchstem Maße
                              Compiler-spezifisch.

                              nein, deine Schlussfolgerung ist so nicht ganz richtig. Der Compiler muss
                              die Konvention umsetzen, die das jeweilige Zielsystem verwendet. Er hat
                              also nicht die Möglichkeit zu wählen.

                              Wer sagt das? Der Standard nicht.

                              [...] um festzustellen, an welcher Stelle man den Funktions-Aufruf
                              fortsetzen muss.

                              Genau dafür geben die printf()-Funktionen doch die Anzahl der
                              geschriebenen Zeichen als Funktionsergebnis zurück.

                              Tut es nicht. Im Fehlerfall wird ein negativer Wert zurückgegeben.

                              Bestens vertraut sind mir deshalb Konstruktionen wie etwa

                              CHAR *str;
                              [...]
                              str += sprintf("Pattern Line 1", var1, var2);
                              str += sprintf("Pattern Line 2", var3, var4);
                              str += sprintf("Pattern Line 3", var5, var6);
                              ...

                              Über den Code solltest du nochmal nachdenken. Der ist so, wie der da steht,
                              totaler Quatsch.

                              再见,
                               克里斯蒂安

                              --
                              Block-Installation Nr. 5 | Renovation der Mensa-Nord
                              Das Leben ist wie ein Kartenspiel: was dir gegeben wurde, ist vorbestimmt. Doch wie du damit spielst, ist deine Entscheidung.
                              http://wwwtech.de/
                              1. Moin,

                                nein, deine Schlussfolgerung ist so nicht ganz richtig. Der Compiler muss die Konvention umsetzen, die das jeweilige Zielsystem verwendet. Er hat also nicht die Möglichkeit zu wählen.
                                Wer sagt das? Der Standard nicht.

                                Braucht er auch nicht. Ein Compiler, der eine andere Konvention als die des gewünschten Zielsystems verwendet, erzeugt Programmcode, der nicht lauffähig ist, weil jede Übergabe von Integerwerten an Systemfunktionen Unsinn übergibt.

                                CHAR *str;
                                [...]
                                str += sprintf("Pattern Line 1", var1, var2);
                                str += sprintf("Pattern Line 2", var3, var4);
                                str += sprintf("Pattern Line 3", var5, var6);
                                ...

                                Über den Code solltest du nochmal nachdenken. Der ist so, wie der da steht, totaler Quatsch.

                                Schön. Produziert aber in Hunderten von Exemplaren seit Jahren tadellos die erwünschten Ergebnisse. Und -auf die Gefahr, dass ich mich wiederhole- allein darauf kommt es an.

                                Zitat aus der Online-Hilfe zu Borland C++ 5.01:

                                | Rückgabewert:
                                 | sprintf() liefert liefert die Anzahl der ausgegebenen Zeichen zurück,
                                 | wobei das abschließende Nullzeichen nicht mitgezählt wird.
                                 | Im Fehlerfall ist das Funktionsergebnis EOF.

                                EOF ist tatsächlich als -1 definiert.

                                Über deine obige Aussage solltest du nochmal nachdenken. Die ist so, wie sie da steht, totaler Quatsch.
                                Es sei denn, du erklärst mir jetzt noch, was bei sprintf() für Fehler auftreten sollen, solange der Format-String korrekt ist. Aber da dürftest du's schwer haben. ;-)

                                Schönes Wochenende noch,

                                Martin

                                --
                                Was ist wichtiger: Die Sonne oder der Mond?
                                Der Mond. Denn er scheint nachts. Die Sonne dagegen scheint tagsüber, wenn es sowieso hell ist.
                                1. 你好 Der,

                                  nein, deine Schlussfolgerung ist so nicht ganz richtig. Der Compiler
                                  muss die Konvention umsetzen, die das jeweilige Zielsystem verwendet.
                                  Er hat also nicht die Möglichkeit zu wählen.
                                  Wer sagt das? Der Standard nicht.

                                  Braucht er auch nicht. Ein Compiler, der eine andere Konvention als die
                                  des gewünschten Zielsystems verwendet, erzeugt Programmcode, der nicht
                                  lauffähig ist, weil jede Übergabe von Integerwerten an Systemfunktionen
                                  Unsinn übergibt.

                                  Nein, das ist nicht wahr, und das weisst du. Jedem Compiler steht es frei,
                                  intern eine der drei Formate zu benutzen und sie bei Bedarf anzupassen; wäre
                                  ja auch schlimm, wenn das nicht so wäre, stell dir vor, was auf einem System
                                  passieren würde, dass vollständig mit BCD arbeitet...

                                  [...] str += sprintf("Pattern Line 1", var1, var2);
                                  Über den Code solltest du nochmal nachdenken. Der ist so, wie der da
                                  steht, totaler Quatsch.

                                  Schön. Produziert aber in Hunderten von Exemplaren seit Jahren tadellos
                                  die erwünschten Ergebnisse.

                                  Und ich wette mit dir, dass das nicht der Fall ist. sprintf() übernimmt als
                                  erstes Argument den Buffer, in den es schreiben soll...

                                  Über deine obige Aussage solltest du nochmal nachdenken. Die ist so, wie
                                  sie da steht, totaler Quatsch.

                                  Nein, nicht wirklich - die Parameter solltest du schon richtig übergeben,
                                  sonst funktioniert gar nix >;)

                                  再见,
                                   克里斯蒂安

                                  --
                                  Block-Installation Nr. 5 | Renovation der Mensa-Nord
                                  Das Sein entsteht aus dem Nicht-Sein.
                                  http://wwwtech.de/
                                  1. Hallo,

                                    Braucht er auch nicht. Ein Compiler, der eine andere Konvention als die
                                    des gewünschten Zielsystems verwendet, erzeugt Programmcode, der nicht
                                    lauffähig ist, weil jede Übergabe von Integerwerten an Systemfunktionen
                                    Unsinn übergibt.

                                    Nein, das ist nicht wahr, und das weisst du. Jedem Compiler steht es frei,
                                    intern eine der drei Formate zu benutzen und sie bei Bedarf anzupassen; wäre
                                    ja auch schlimm, wenn das nicht so wäre, stell dir vor, was auf einem System
                                    passieren würde, dass vollständig mit BCD arbeitet...

                                    Ja und? Für so ein System hätte ein Compiler gefälligst Code zu erzeugen, der ebenfalls mit BCD-Arithmetik arbeitet. Das ist nun einmal meine Überzeugung. Intern ein anderes Format zu verwenden und bei jedem Systemaufruf umzuwandeln wäre zwar theoretisch möglich, aber praktisch völliger Blödsinn.

                                    [...] str += sprintf("Pattern Line 1", var1, var2);
                                    Und ich wette mit dir, dass das nicht der Fall ist. sprintf() übernimmt als erstes Argument den Buffer, in den es schreiben soll...

                                    Oha... erwischt. ;-)
                                    Es hätte so heißen sollen:

                                    str += sprintf(str, "Pattern Line 1", var1, var2);

                                    Ja, den buffer hatte ich vor lauter lass-mich-auch-mal völlig vergessen. Dann entschuldige bitte meine verbale Backpfeife - ich habe angesichts deiner Kritik nach ganz anderen subtilen Fehlermöglichkeiten gesucht und dabei das Offensichtlichste übersehen.

                                    Schönes Wochenende noch,

                                    Martin

                                    --
                                    Die letzten Worte der Challenger-Crew:
                                    Lasst doch mal die Frau ans Steuer!
                                    1. 你好 Der,

                                      Braucht er auch nicht. Ein Compiler, der eine andere Konvention als
                                      die des gewünschten Zielsystems verwendet, erzeugt Programmcode, der
                                      nicht lauffähig ist, weil jede Übergabe von Integerwerten an
                                      Systemfunktionen Unsinn übergibt.

                                      Nein, das ist nicht wahr, und das weisst du. Jedem Compiler steht es
                                      frei, intern eine der drei Formate zu benutzen und sie bei Bedarf
                                      anzupassen; wäre ja auch schlimm, wenn das nicht so wäre, stell dir
                                      vor, was auf einem System passieren würde, dass vollständig mit BCD
                                      arbeitet...

                                      Ja und? Für so ein System hätte ein Compiler gefälligst Code zu
                                      erzeugen, der ebenfalls mit BCD-Arithmetik arbeitet.

                                      Nein, das muss transparent sein. Dafür wurde C geschaffen: als
                                      plattformunabhängige Sprache. Du hast die falschen Erwartungen, wenn du
                                      das so willst, solltest du nicht C programmieren.

                                      Das ist nun einmal meine Überzeugung.

                                      Deine Überzeugung deckt sich aber nicht mit den Fakten. C-Compiler dürfen
                                      nicht tun, was sie wollen, sie sind an recht strenge Richtlinien gebunden.
                                      Und der Code, den du schreibst, ist in diesem Fall einfach
                                      Compiler-spezifisch, die Stelle im Standard ist eindeutig.

                                      Es hätte so heißen sollen:

                                      str += sprintf(str, "Pattern Line 1", var1, var2);

                                      Das dachte ich mir, wollte es dir aber auch nicht zu leicht machen ^^

                                      再见,
                                       克里斯蒂安

                                      --
                                      Block-Installation Nr. 5 | Renovation der Mensa-Nord
                                      Kommt ein Vektor zur Drogenberatung: "Hilfe, ich bin linear abhaengig!"
                                      http://wwwtech.de/
                                2. Hi Leute!

                                  Schön. Produziert aber in Hunderten von Exemplaren seit Jahren tadellos die erwünschten Ergebnisse. Und -auf die Gefahr, dass ich mich wiederhole- allein darauf kommt es an.

                                  Wie du meinst. Ich schreibe lieber sauberen Code, da weiß ich, dass er auch bei tausenden Programmläufen immer noch wie beabsichtigt funktioniert.

                                  Zitat aus der Online-Hilfe zu Borland C++ 5.01:

                                  ^
                                  Ich glaube, dass genau hier -----------------+ ein gravierendes Problem einsetzt: Ich hatte den BCC auch erst auf meiner alten DOSe, aber die Umsetzung neuer Sprachfeatures (wie ISO C99) ist bei einem so alten Compiler (der BCC 5.5 ist laut Borland von 2000) erwarten? Schnapp dir mal einen richtigen C-Compiler.

                                  EOF ist tatsächlich als -1 definiert.

                                  Muss es allerdings nicht.

                                  Es sei denn, du erklärst mir jetzt noch, was bei sprintf() für Fehler auftreten sollen, solange der Format-String korrekt ist. Aber da dürftest du's schwer haben. ;-)

                                  CHAR *str;

                                  [...]
                                  str += sprintf("Pattern Line 1", var1, var2);
                                  str += sprintf("Pattern Line 2", var3, var4);
                                  str += sprintf("Pattern Line 3", var5, var6);

                                    
                                  Wo ist denn str dimensioniert? Soweit ich diesen Code richtig verstehe, ist nach diesen drei Zeilen die Adresse, auf die str zeigt, einfach nur weitergerückt.  
                                    
                                  Viele Grüße,  
                                  Robert
                                  
                                  1. Hi,

                                    Schön. Produziert aber in Hunderten von Exemplaren seit Jahren tadellos die erwünschten Ergebnisse. Und -auf die Gefahr, dass ich mich wiederhole- allein darauf kommt es an.
                                    Wie du meinst. Ich schreibe lieber sauberen Code, da weiß ich, dass er auch bei tausenden Programmläufen immer noch wie beabsichtigt funktioniert.

                                    Ich auch. Ich weiß, was mein Compiler verspricht, und das hält er auch. Ob irgendein Standard dasselbe sagt, ist zweitrangig, denn die große weite Welt sieht -wenn überhaupt- nur den vom Compiler erzeugten ausführbaren Code. Solange Sourcecode, Compiler und Zielsystem also zueinander passen, ist alles in Butter. Und darauf achte ich auch.

                                    Zitat aus der Online-Hilfe zu Borland C++ 5.01:
                                                                                 ^
                                    Ich glaube, dass genau hier -----------------+ ein gravierendes Problem einsetzt: Ich hatte den BCC auch erst auf meiner alten DOSe, aber die Umsetzung neuer Sprachfeatures (wie ISO C99) ist bei einem so alten Compiler (der BCC 5.5 ist laut Borland von 2000) erwarten? Schnapp dir mal einen richtigen C-Compiler.

                                    Warum sollte ich? Er leistet alles, was ich bisher von ihm erwartet habe. Er übersetzt auch moderne, aktuelle Windows-Projekte problemlos, wenn ich ihm die dazu nötigen Win32-Headerfiles anbiete. Was will ich mehr? Nur weil ein Programm alt ist, muss es noch lange nicht schlecht sein. Manchmal ist sogar das Gegenteil der Fall: Ich benutze heute noch Word97, weil ich alle nachfolgenden Versionen für Rückschritte in Zuverlässigkeit und Usability halte.

                                    EOF ist tatsächlich als -1 definiert.
                                    Muss es allerdings nicht.

                                    Stimmt. Ist auch nebensächlich, da es im genannten Beispiel nicht auftreten kann.

                                    CHAR *str;

                                    [...]
                                    str += sprintf("Pattern Line 1", var1, var2);
                                    str += sprintf("Pattern Line 2", var3, var4);
                                    str += sprintf("Pattern Line 3", var5, var6);

                                    
                                    >   
                                    > Wo ist denn str dimensioniert?  
                                      
                                    In den ausgelassenen Zeilen in [...]. Das ist auch unerheblich. Ich wollte lediglich ausdrücken, dass str vom Typ CHAR\* ist. Dass dieser Pointer auf einen ausreichend(!) groß reservierten Speicherbereich zeigt, habe ich als selbstverständlich vorausgesetzt. Mir ging es nur darum, dass der Rückgabewert von sprintf() genau das gleiche leistet, was du mir vorher mit %n erklärt hattest.  
                                      
                                    Schönen Abend noch,  
                                      
                                     Martin  
                                    
                                    -- 
                                    Frauen sind wie Elektrizität: Fasst man sie an, kriegt man eine gewischt.  
                                      
                                    
                                    
  3. Hallo,

    Ich schäme mich ja ein wenig diese Frage hier zu stellen, aber ich suche seit stunden rum und finde nichts dazu. Ich habe früher hauptsächlich java u.ä programmiert und jetzt gezwungernermaßen c++.
    Nur bekomme ich die simpelste Aufgabe nicht hin...Ich will einen Dateinamen zusammensetzen aus ein paa variablen, also aus char* und aus ein paar int-werten. So einfach geht das ja nun leider nicht, wie ich gemerkt habe. Der + operator funktioniert nicht für char, strcat funktioniert nicht für char pointer und int werte lassen sie eh nicht in char* casten wie es mir vorkommt...kann mir jemand helfen ?

    das Problem in einfachen Worten :
    Strings zusammensetzen aus einzelnen chars* vermischt mit ints ...

    Vielen Dank !

    Gruss
    Peter

    iCh wwürde eher die String-Klasse benutzten. Die kann man einfach mit den +-operator verknüpfen: #include <string>

  4. Moin Peter!

    […] Ich will einen Dateinamen zusammensetzen aus ein paa variablen, also aus char* und aus ein paar int-werten. So einfach geht das ja nun leider nicht, wie ich gemerkt habe. Der + operator funktioniert nicht für char,

    Doch, er addiert die Werte der beiden Zeichen, aber er macht nicht zwei Zeichen daraus.

    strcat funktioniert nicht für char pointer

    Sollte es aber.

    und int werte lassen sie eh nicht in char* casten wie es mir vorkommt...kann mir jemand helfen ?

    Die Lösung deines Problemes heißt std::stringstream. Diese Dinger lassen sich wie ganz normale Ein-/Ausgabe-Streams verwenden, sind allerdings mit std::string gekoppelt. Bsp.:

      
    #include <sstream>  
    #include <string>  
    #include <iostream>  
      
    char name[] = "Peter";  
    int i = 23;  
    double pi = 3.;  
    std::stringstream sstr;  
      
    sstr << "Hallo " << name << " der " << i << "te, PI=" << pi;  
      
    std::cout << sstr.str() << '\n';  
    // str() gibt den Inhalt des Streams als std::string zurück  
    // obiges gibt folgendes aus:  
    // "Hallo Peter der 23te, PI=3."  
    
    

    Viele Grüße,
    Robert

    1. Hallo Robert,

      double pi = 3.;

      Knauser, zumindest auf 3.14 hättest Du das nähern können. ;-)

      Viele Grüße,
      Christian

      1. Hallo Christian!

        double pi = 3.;

        Knauser, zumindest auf 3.14 hättest Du das nähern können. ;-)

        Kennst du nicht den Ausspruch aus den Simpsons „Pi ist genau 3!“

        Viele Grüße,
        Robert

      2. Hallo,

        double pi = 3.;
        Knauser, zumindest auf 3.14 hättest Du das nähern können. ;-)

        wieso?
        Für grobe Abschätzungen gelten doch die Faustregeln

        pi = 3
         2pi = 6
         3pi = 10
         pi² = 10

        Für Überschlagsrechnungen ist das meistens gut genug. :-)
        So long,

        Martin

        --
        Okay, Alkohol ist keine Antwort.
        Aber manchmal vergisst man beim Trinken wenigstens die Frage.