Wieso gibt es bei printf eigentlich keine autotyp Erkennung?



  • Was mich an C etwas stört ist, dass man bei printf immer ganz genau angeben muss, als was man eine Variable ausgeben möchte.

    Hat man z.B. einen String, dann muss man %s verwenden.
    Hat man ein int, dann %i.
    Ist es ein unsigned int, dann %ui
    bei einem char, ein %c
    für float, ein %f
    usw. …

    Dabei kennt doch der C Compiler die Typen der Variblen doch ganz genau und könnte daher zur Compilezeit einen Autotyp Bezeichner, nennen wir ihn mal %a selbst passend umbenennen.
    Dann müsste sich der Programmierer darüber nicht immer Gedanken machen.
    Und nur dann, wenn der Programmierer etwas anderes ausgegeben haben will.
    Z.B. von einem Zeichen den int Wert, anstatt den Buchstaben, dann könnte man das ja so per expliziter Typumwandlung lösen:

    char z = "x"
    printf("Zeichen = %a", (int) z);

    Obwohl z ein Char ist, würde dann anstatt dem x der entsprechende ASCII Wert ausgegeben werden.

    So wäre das alles viel einfacher und man müsste sich nicht dutzende von %* merken und sich darüber den Kopf zerbrechen, was man denn nun genau ausgeben will.
    Die Typen sind ja im Prinzip durch die Variablendeklaration schon eindeutig definiert und nur dann, wenn man explizit was anderes ausgegeben haben möchte, könnte man einen cast verlangen.

    Gibt es irgendeinen Grund, warum so ein Autotyp noch nie in den C Standard aufgenommen wurde bzw. ob sich darüber beim C Komitee überhaupt schon jemand Gedanken gemacht hat?


  • Mod

    Du denkst nicht weit genug. Das ist keine absichtliche Beschränkung von printf, sondern eine Beschränkung der Sprache C an sich. Denn wenn die Daten beim printf ankommen, hat dieses keine Möglichkeit, die Typen zu erkennen. printf ist auch nur eine ganz normale Funktion mit variabler Argumentenliste. Das ist eben die einzige in C vorgesehene Möglichkeit, eine unspezifizierte Anzahl an Argumenten mit unspezifizierten Typen an eine Funktion zu übergeben.
    An sich wäre der Compiler natürlich schon schlau genug, das zu machen. Viele Compiler prüfen (zumindest mit ausreichend hohem Warnlevel) ob Formatstring und Argumente zusammen hängen. Aber es ist eben nicht möglich, ein printf zu schreiben, was dies beherrscht.



  • SeppJ schrieb:

    Du denkst nicht weit genug. Das ist keine absichtliche Beschränkung von printf, sondern eine Beschränkung der Sprache C an sich. Denn wenn die Daten beim printf ankommen, hat dieses keine Möglichkeit, die Typen zu erkennen. printf ist auch nur eine ganz normale Funktion mit variabler Argumentenliste. Das ist eben die einzige in C vorgesehene Möglichkeit, eine unspezifizierte Anzahl an Argumenten mit unspezifizierten Typen an eine Funktion zu übergeben.
    An sich wäre der Compiler natürlich schon schlau genug, das zu machen. Viele Compiler prüfen (zumindest mit ausreichend hohem Warnlevel) ob Formatstring und Argumente zusammen hängen. Aber es ist eben nicht möglich, ein printf zu schreiben, was dies beherrscht.

    Das soll ja auch nicht das printf beherrschen, sondern der Compiler soll es für printf passend machen.

    Vielleicht etwas vergleichbar mit dem C-Präprozessor, von dem wissen die C Funktionen auch nichts, wenn im Code ein #define PI 3.141 steht und PI dann in beim Funktionsaufruf übergeben wird.


  • Mod

    Tja, gibt's eben nicht. Die Standardbibliothek hält sich an die Regeln der Sprache. Da gibt es eben keine Sonderregeln, bloß weil eine Funktion sich printf nennt, dass der Compiler in ihren Argumenten rumpfuschen darf.

    Noch ein paar Punkte, die mir dazu einfallen, die zwar lösbar wären, aber eben noch mehr Sonderregeln verlangen:
    -Der Formatstring muss ja nicht unbedingt eine Konstante sein. Man könnte natürlich sagen, dass das eben nur bei Konstanten gemacht wird. Weitere Sonderregel.
    -Wenn es eine Konstante ist, darf der Compiler dann Konstanten ändern? Oder macht er jeweils eine neue, kopierte Konstante mit diesen Ersetzungen?
    -Was passiert im Folgenden?

    const char* format = "%a %a";
    int i; double d; char c;
    printf(format, i ,d);
    printf(format, i ,c);
    

    -Wie hält man es mit Sub-Spezifikatoren?

    Ist alles regelbar, aber es wäre eine lange Sammlung von Sonderregeln. Es ist nicht so einfach, wie du denkst.



  • Autotyp schrieb:

    [...] nur dann, wenn man explizit was anderes ausgegeben haben möchte, könnte man einen cast verlangen.

    Aha. In was caste ich einen unsigned damit ich "%x" bekomme?



  • Gar nicht. Casten birgt immer die Gefahr der Verfälschung der Werte/Inhalte.
    Übergib einen unsigned int für "%x", unsigned long für "%lx","%lu" usw. und fertig.





  • Swordfish schrieb:

    Autotyp schrieb:

    [...] nur dann, wenn man explizit was anderes ausgegeben haben möchte, könnte man einen cast verlangen.

    Aha. In was caste ich einen unsigned damit ich "%x" bekomme?

    Wenn du ein unsigned int als Hexwert darstellen möchtest, dann schreibst du folgendes:

    unsigned int i = 10;
      printf("%a\n", (hex) i);
    

    Der Compiler hat dann das

    printf("%a\n", (hex) i);
    

    als

    printf("%x\n", i);
    

    auszuwerten.

    Das (hex) wird dann entsprechend zur der %a Regel Einführung auch eingeführt.
    Für die Oktaldarstellung kann man ähnliches vereinbaren.
    Oder man macht noch eine allgemeine Regel, z.b. (base 4).



  • SeppJ schrieb:

    Tja, gibt's eben nicht. Die Standardbibliothek hält sich an die Regeln der Sprache. Da gibt es eben keine Sonderregeln, bloß weil eine Funktion sich printf nennt, dass der Compiler in ihren Argumenten rumpfuschen darf.

    Ja, es würde halt dem Programmierer viel Arbeit abnehmen und unnötige Compilerfehlermeldungen vermeiden und somit die Arbeit beschleunigen.

    -Der Formatstring muss ja nicht unbedingt eine Konstante sein. Man könnte natürlich sagen, dass das eben nur bei Konstanten gemacht wird. Weitere Sonderregel.

    Die Frage ist halt, ob man da nicht irgendwelche Lücken aufreißt, wenn man es bei Variablen Strings erlauben würde.

    -Wenn es eine Konstante ist, darf der Compiler dann Konstanten ändern? Oder macht er jeweils eine neue, kopierte Konstante mit diesen Ersetzungen?

    Der Compiler darf den Quelltext nicht verändern, sondern er soll aus dem Quelltext lesen und das dann entsprechend interpretieren.

    Wenn man den Quelltext verändern dürfte, dann könnte man so etwas ja schon heute selber machen, in dem man sich einfach ein Tool schreibt, dass alle %a in entsprechende Werte ersetzt.
    Das will man als Coder aber vielleicht gar nicht, weil man sich z.B. später umentscheidet.
    Deswegen sollte der Compiler diese Aufgabe übernehmen.

    Für folgendes etwas aber, wäre es sinnvoll, wenn der Compiler aus der Konstante Kopien anfertig.

    -Was passiert im Folgenden?

    const char* format = "%a %a";
    int i; double d; char c;
    printf(format, i ,d);
    printf(format, i ,c);
    

    -Wie hält man es mit Sub-Spezifikatoren?

    eine für das format für

    printf(format, i ,d);
    

    und eine andere, für das format für
    [/quote]
    printf(format, i ,c);
    [/code]



  • Also ich mach mich jetzt mal unbeliebt... los geht's.
    Es gab da nämlich einen, der hat solche und ähnliche Überlegungen genommen, und sich angesehen wie man da möglichst flexible Lösungen dafür bauen könnte. Also möglichst nicht Spezialbehandlung für zb Format-Strings, sondern der Sprache allgemeine Konstrukte hinzufügen mit denen man dann einen sicheren Ersatz für Dinge wie printf basteln kann -- und noch viel mehr.

    Der Mann hiess Stroustrup, was dabei raus kam C++, und der Ersatz für printf std::ostream bzw. boost::format .

    🤡



  • hustbaer schrieb:

    Der Mann hiess Stroustrup, was dabei raus kam C++, und der Ersatz für printf std::ostream bzw. boost::format .

    Nein, raus kam std::ostream und die Leute verwendeten weiterhin printf , weil es einfach viel kürzer, bequemer und semantisch korrekter (Trennung von Darstellung und Daten) ist.

    Jede Sprache, die keinen Stroustrup hat, der sich gegen printf-artige Konstrukte wehrt, hat bessere Alternativen. Siehe z.B. C#/Python/D/Rust Formatstrings.



  • Also das System.out.println(); in Java finde ich sehr schön,
    da kann man die Variablen und Stringkonstanten in der Klammer einfach
    mit einem + zusammenhängen und muss sich ansonsten keine weiteren Gedanken darüber machen.



  • Autotyp schrieb:

    Also das System.out.println(); in Java finde ich sehr schön,
    da kann man die Variablen und Stringkonstanten in der Klammer einfach
    mit einem + zusammenhängen und muss sich ansonsten keine weiteren Gedanken darüber machen.

    Das liegt dann aber an der Stringbehandlung von Java und ist kein Feature von System.out.println()



  • @scanf-lover


Anmelden zum Antworten