Sizeof 'A' (war Cidiosyncracies)

Schnelle objektorientierte, kompilierende Programmiersprache.
nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Cidiosyncracies

Beitrag von nufan » Di Feb 18, 2014 8:50 pm

mfro hat geschrieben:c ist (auf Maschinen, auf denen der Typ char signed ist, das ist nicht immer so) 0xff, also -1, richtig.

Code: Alles auswählen

int printf(const char *format, ...);
Printf() ist eine variadische Funktion. Bei variadischen Funktionen findet für die "..."-Parameter immer eine Typpromotion, in diesem Fall also "int promotion" statt - im printf()-Rumpf landet also ein int mit dem Wert -1 (0xffffffff).
Das versteh ich nicht ganz... ich dachte mit der expliziten Zuweisung an die char-Variable wäre das erledigt und mein Wert steht in einer 1 Byte Variable? Wieso wird dann printf() ein 4 Byte int übergeben?

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Cidiosyncracies

Beitrag von mfro » Di Feb 18, 2014 9:19 pm

dani93 hat geschrieben: Das versteh ich nicht ganz... ich dachte mit der expliziten Zuweisung an die char-Variable wäre das erledigt und mein Wert steht in einer 1 Byte Variable? Wieso wird dann printf() ein 4 Byte int übergeben?
Das Stichwort heißt "variadic function" - also eine Funktion, die eine "Ellipsis" (...) als Parameter hat (an den beliebig viele oder auch kein Wert übergeben werden kann).

Im Standard ist definiert, daß bei variadische Funktionen für die "Ellipsis"-Parameter Variablen-Promotion stattfinden soll, d.h. aus char werden ints, aus unsigned chars unsigned ints und aus floats werden doubles. Das macht den Compilerbauern die Implementierung von variadischen Funktionen wesentlich einfacher.

Übrigens: kein Compiler den ich kenne - mit Ausnahme eines uralten Z80 CP/M 8-Bit Compilers, für den das Nachfolgende (aber sonst auch nix mehr ;) ) keine Rolle spielt - legt bei einem char als Funktionsparameter genau ein Byte auf den Stack.

Das würde dazu führen, daß ein evt. nachfolgender, längerer Parameter (ein int, z.B.) auf einer ungeraden Adresse landen würde.

Viele Prozessorarchitekturen quittieren einen Word-Zugriff auf eine ungerade (Stack-) Adresse mit einem Adreßfehler, alle anderen, die damit zurechtkämen, mit erheblichen Performance-Einschränkungen (der Prozessor macht dann aus einem int-Zugriff vier aufeinanderfolgende Byte-Zugriffe). Compilerbauer müssen das demnach auf jeden Fall vermeiden.
Auf den Stack gepackt wird also in jedem Fall mindestens ein short, meist aber ein int (viele Architekturen sind nur mit 8 oder gar 16 Byte Stack-Alignment schnell). Die "oberen" Bits werden von der aufgerufenen Funktion einfach ignoriert.

"Stack Sparen" kann man also nicht, wenn man Funktionen mit char-Parametern definiert.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Cidiosyncracies

Beitrag von Xin » Mi Feb 19, 2014 12:07 pm

mfro hat geschrieben: Dann kann jetzt sicher jemand die Preisfrage beantworten: wie lautet die Ausgabe: "0xffffffff 0xff" oder "0xff 0xff"?

Code: Alles auswählen

const unsigned char c = 0xff;
printf("%02x %02x\n", c, (char) c);
0xff 0xff... ein unsigned char lässt sich ja 1:1 in ein int transformieren.

Ich gehe davon aus, dass Du hier eine kleine Sammlung hast? Ich schiele vorsichtig auf's Wiki. ^^
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Cidiosyncracies

Beitrag von mfro » Mi Feb 19, 2014 5:25 pm

Xin hat geschrieben:
mfro hat geschrieben: Dann kann jetzt sicher jemand die Preisfrage beantworten: wie lautet die Ausgabe: "0xffffffff 0xff" oder "0xff 0xff"?

Code: Alles auswählen

const unsigned char c = 0xff;
printf("%02x %02x\n", c, (char) c);
0xff 0xff... ein unsigned char lässt sich ja 1:1 in ein int transformieren.
Leider falsch ;).

c ist ein unsigned char. 0xff = 255, macht bei der "unsigned int"-Promotion Richtung "variadic function" immer noch 255.
Der Cast nach char (auf den meisten Maschine vorzeichenbehaftet/signed) macht aus "(unsigned char) 0xff" (der zweiten Ausgabe) "(signed char) 0xff" = -1, darauf folgt die "int promotion" -> (int) -1.

Ausgegeben wird also "0xff 0xffffffff" ;)

Xin hat geschrieben:Ich gehe davon aus, dass Du hier eine kleine Sammlung hast? Ich schiele vorsichtig auf's Wiki. ^^
Wenn Du glaubst, ich würde Liste führen, mit welchen "C-quirks" ich schon alles auf die Fresse geflogen bin, muß ich dich leider enttäuschen ;).

Vieles fällt mir wieder ein, wenn ich mich durchs Forum lese und manches hat sich so eingebrannt, daß es mir immer präsent ist...

Ich fürchte, als "Wiki-Betreuer" bin ich ungeeignet, aber falls jemand meine Ergüsse in Reinform bringen und übertragen will, ist er herzlich eingeladen. Ansonsten würde ich - falls gewünscht - hier halt immer mal wieder einen Beitrag anhängen, wenn mir was ein- oder auffällt (oder wenn ich mal wieder so richtig auf die Schnauze geflogen bin ;) ).
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Cidiosyncracies

Beitrag von Xin » Mi Feb 19, 2014 6:48 pm

mfro hat geschrieben:
Xin hat geschrieben:
mfro hat geschrieben: Dann kann jetzt sicher jemand die Preisfrage beantworten: wie lautet die Ausgabe: "0xffffffff 0xff" oder "0xff 0xff"?

Code: Alles auswählen

const unsigned char c = 0xff;
printf("%02x %02x\n", c, (char) c);
0xff 0xff... ein unsigned char lässt sich ja 1:1 in ein int transformieren.
Leider falsch ;).

c ist ein unsigned char. 0xff = 255, macht bei der "unsigned int"-Promotion Richtung "variadic function" immer noch 255.
Der Cast nach char (auf den meisten Maschine vorzeichenbehaftet/signed) macht aus "(unsigned char) 0xff" (der zweiten Ausgabe) "(signed char) 0xff" = -1, darauf folgt die "int promotion" -> (int) -1.

Ausgegeben wird also "0xff 0xffffffff" ;)
*narf* Nicht mein Tag heute... ^^
mfro hat geschrieben:Ansonsten würde ich - falls gewünscht - hier halt immer mal wieder einen Beitrag anhängen, wenn mir was ein- oder auffällt (oder wenn ich mal wieder so richtig auf die Schnauze geflogen bin ;) ).
Ist gewünscht. :-)
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Sizeof 'A' (war Cidiosyncracies)

Beitrag von mfro » Mi Feb 19, 2014 7:18 pm

Na dann 8-) .

Hier ist noch ein Netter aus der gleichen Abteilung:

Code: Alles auswählen

#include <stdio.h>

int main(int argc, char *argv[])
{
    const char c = 0xff;
    const unsigned char d = 0xff;

    printf(" %d\n", c >> 9);
    printf(" %d\n", d >> 9);

    return 0;
}
Was kommt denn hier wohl raus?
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Sizeof 'A' (war Cidiosyncracies)

Beitrag von Xin » Mi Feb 19, 2014 8:49 pm

-1 und 0 erwarte ich. (was wie man sieht ja nichts zu bedeuten hat :-))
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Sizeof 'A' (war Cidiosyncracies)

Beitrag von mfro » Mi Feb 19, 2014 8:55 pm

Xin hat geschrieben:-1 und 0 erwarte ich. (was wie man sieht ja nichts zu bedeuten hat :-))
... und das ist völlig richtig!

Joker-Frage: warum gibt auch der standardkonformste und penibelste Compiler trotz "-Wall" keine Warnung aus, obwohl man eine char Variable (die ja nur 8 Bits hat) um 9 Bits shiftet?
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Sizeof 'A' (war Cidiosyncracies)

Beitrag von Xin » Mi Feb 19, 2014 9:14 pm

mfro hat geschrieben:Joker-Frage: warum gibt auch der standardkonformste und penibelste Compiler trotz "-Wall" keine Warnung aus, obwohl man eine char Variable (die ja nur 8 Bits hat) um 9 Bits shiftet?
Keine Ahnung, aber nur weil das Ergebnis sich nicht mehr ändert, wird die Aufgabe doch nicht falsch!? Ein Compiler meckert - denke ich - auch nicht, wenn man c *= 1 oder c += 0 schreibt.

Lass Dir mit der Antwort mehr Zeit - damit auch andere eine Schätzung abgeben können.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Sizeof 'A' (war Cidiosyncracies)

Beitrag von mfro » Mi Feb 19, 2014 9:37 pm

Xin hat geschrieben:
mfro hat geschrieben:Joker-Frage: warum gibt auch der standardkonformste und penibelste Compiler trotz "-Wall" keine Warnung aus, obwohl man eine char Variable (die ja nur 8 Bits hat) um 9 Bits shiftet?
Keine Ahnung, aber nur weil das Ergebnis sich nicht mehr ändert, wird die Aufgabe doch nicht falsch!? Ein Compiler meckert - denke ich - auch nicht, wenn man c *= 1 oder c += 0 schreibt.

Lass Dir mit der Antwort mehr Zeit - damit auch andere eine Schätzung abgeben können.
Tip: ein Shift, der über die Breite des Datentyps des Operanden hinausgeht, ist "undefined behaviour" und _muß_ lt. Standard eine Warnung erzeugen.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Antworten