Gegeben folgender fehlerhafte aber compilierbare Code -
es fehlen ein paar casts.
Ich bin gefragt worden, warum es im Code unten
augenscheinlich ausreicht, jeweils nur die erste
printf-gleitpunkt-Ausgabe mit korrektem cast
durch zufᅵhren und bei der jeweils zweiten
den cast wegzulassen und trotzdem das erwartete
Ergebnis lesen zu kᅵnnen.
Und die nᅵchste Frage ist:
Wieso man, wenn die a-Fᅵlle mit korrekten casts ausgestattet sind
und die b-Fᅵlle nicht kastet, das selbe Ergebnis fᅵr b wie bei a bekommt.
Gruᅵ Robert
P.S. Ich wᅵrde mich zur Erklᅵrung des Verhaltens ungerne auf
"Da muss du eben den Cast machen, sonst ist es einfach falsch
mit unsicherem Ergebnis" zurᅵckziehen.
#include <stdio.h>
int main(int argc, char** argv ) {
int a=123;
int b=-7;
printf("a als Zeichen: %c\n", a);
printf("a als vorzeichenlose Ganzahl: %u\n", a);
printf("a als Hexadezimalzahl: %x\n", a);
printf("a als vorzeichenbehaftete Ganzzahl: %d \n", a);
printf("Gleitpunktzahl einfache Genauigkeit 2 Nachkommastellen
%.2f\n",(float)a);
printf("Gleitpunktzahl doppelte Genauigkeit exponent. Darst. %E\n",a);
printf("\n \n");
printf("b als Zeichen: %c\n", b);
printf("b als vorzeichenlose Ganzahl: %u\n", b);
printf("b als Hexadezimalzahl: %x\n", b);
printf("b als vorzeichenbehaftete Ganzzahl: %d \n", b);
printf("Gleitpunktzahl einfache Genauigkeit 2 Nachkommastellen
%.2f\n",(float)b);
printf("Gleitpunktzahl doppelte Genauigkeit exponent. Darst. %E\n",b);
return 0;
}
Um das herauszufinden, wirst Du analysieren muessen, was die
printf-Implementierung, die Du benutzt hast, in diesen Faellen tut.
Mit C hat das allerdings nichts zu tun.
[...]
> P.S. Ich w�rde mich zur Erkl�rung des Verhaltens ungerne auf
> "Da muss du eben den Cast machen, sonst ist es einfach falsch
> mit unsicherem Ergebnis" zur�ckziehen.
Das ist aber genau die Antwort auf Deine Frage. So, wie der Code
in Deinem Posting steht, ist sein Verhalten undefiniert, weil die
Typen der Argumente nach Anwendung der 'integer promotions' zT nicht
denen entsprechen, die Argument fuer die entsprechenden 'conversion
specifier' haben sollen. Um es mal mit einen Beispiel zu versuchen:
?aufgebaut so nicht Deutschen im Saetze werden Warum
Schliesslich 'funktioniert' das doch auch und ueberhaupt handelt
sich bloss um von n denkbaren, grundsaetzlich willkuerlichen
Konventionen. Genauso willkuerlich wie die Konvention, nach der
2 + 7 = 9
eine wahre Aussage darstellt.
Siehe unten. Es _sollte_ nicht gehen.
> Und die nächste Frage ist:
>
> Wieso man, wenn die a-Fälle mit korrekten casts ausgestattet sind
> und die b-Fälle nicht kastet, das selbe Ergebnis für b wie bei a bekommt.
>
> Gruß Robert
>
> P.S. Ich würde mich zur Erklärung des Verhaltens ungerne auf
> "Da muss du eben den Cast machen, sonst ist es einfach falsch
> mit unsicherem Ergebnis" zurückziehen.
>
>
>
> #include <stdio.h>
>
> int main(int argc, char** argv ) {
>
> int a=123;
> int b=-7;
>
> printf("a als Zeichen: %c\n", a);
> printf("a als vorzeichenlose Ganzahl: %u\n", a);
> printf("a als Hexadezimalzahl: %x\n", a);
> printf("a als vorzeichenbehaftete Ganzzahl: %d \n", a);
Bis hier erwartet printf anhand der Umwandlungen immer ein int, dass
dann irgendwie gecastet wird. Dabei ist zu beachten, dass alle
Ganzzahltypen kleiner als int bei Übergabe als va-Argument zu int
umgewandelt werden.
> printf("Gleitpunktzahl einfache Genauigkeit 2 Nachkommastellen
> %.2f\n",(float)a);
Und hier wird a explizit in ein float umgewandelt, dass allerdings, da
va-Arg, implizit in double umgewandelt wird.
> printf("Gleitpunktzahl doppelte Genauigkeit exponent. Darst. %E\n",a);
>
Das hier sollte nicht funktionieren. Möglicherweise ein kaputter
Compiler. Mit dem tinycc geht es jedenfalls nicht gut (ich bekomme
"NAN"). tendracc liefert ebenfalls Unsinn. Lediglich der gcc ist nicht
davon abzuhalten, a zu double zu konvertieren. Es ist allerdings kein
Bug, das zu tun, da an dieser Stelle sowieso undefiniertes Verhalten
herrscht.
> printf("\n \n");
>
> printf("b als Zeichen: %c\n", b);
> printf("b als vorzeichenlose Ganzahl: %u\n", b);
> printf("b als Hexadezimalzahl: %x\n", b);
> printf("b als vorzeichenbehaftete Ganzzahl: %d \n", b);
> printf("Gleitpunktzahl einfache Genauigkeit 2 Nachkommastellen
> %.2f\n",(float)b);
> printf("Gleitpunktzahl doppelte Genauigkeit exponent. Darst. %E\n",b);
>
Dasselbe wie oben.
>
> return 0;
> }
Zu deiner zweiten Frage: Hier liegt sowieso undefiniertes Verhalten vor.
Der gcc versucht, daraus noch irgendwie einen Sinn zu entnehmen, aber
tinycc und tendracc machen genau das, was du schreibst: Unsinn.
Um das Verhalten genauer zu erklären, kann man sich lediglich den
Quelltext der glibc und das Compilierergebnis des gcc ansehen. Letzteres
geht mit der Option "-S".
HTH,
Markus
--
Nur weil ein Genie nix reißt, muß ja nun nicht gleich jeder Idiot
pausieren... Bully hats ja auch geschafft.
-- gUnter nanonüm in de.alt.anime
F�r die Leute, denen der Umstand erkl�rt werden soll,
vielleicht eine andere Formulierung? Denn wie sollten
sie nachvollziehen, dass die Bedeutung von C-Programmtext
nichts mit C zu tun hat?
"Cs Definition sieht keine Vorhersage eines
bestimmten Ergebnisses f�r diesen nur formal
g�ltigen Programmtext vor. Mehr noch, ...
Deshalb unbedingt ..."
Der gcc konvertiert nicht. Die Zahl, die da ausgegeben wird, ist auch
nicht '123', wovon man sich durch Ersetzen des '%E' durch '%.20E' leicht
überzeugen kann.
Ein double hat heute 64 Bits. '123' ergibt die Bits 0x405EC00000000000.
Diese Bits landen bei 'printf(".2f", (float) a)' auf dem Stack. Der gcc
recycelt nun zufälligerweies Stackpositionen derart, dass die 123 aus
'printf("%E", a)' dort landet, wo die 32 niederwertigsten Bits des
double standen. Die höherwertigsten bleiben noch stehen. 'printf' sucht
nun einen double, bastelt die alten und die neuen Bits zusammen zu
0x405EC0000000007B, und gibt das als double aus, und das ist eben wieder
annähernd 123.
Um es etwas plastischer zu machen: letztlich weist man hier 'printf' an,
nicht (korrekt) initialisierten Speicher zu lesen. Und das ist halt zu
vermeiden. Letztlich gibt der gcc auch für
#include <stdio.h>
int main() {
{
int a = 123;
printf("%d\n", a);
}
{
int b;
printf("%d\n", b);
}
}
zwei identische Werte aus, weil 'b' halt zufällig dort angelegt wird, wo
früher 'a' stand, aber dass das undefiniertes Verhalten ist dürfte jedem
einsichtig sein.
Stefan
>> Das hier sollte nicht funktionieren. Mᅵglicherweise ein kaputter
>> Compiler. Mit dem tinycc geht es jedenfalls nicht gut (ich bekomme
>> "NAN"). tendracc liefert ebenfalls Unsinn. Lediglich der gcc ist nicht
>> davon abzuhalten, a zu double zu konvertieren.
> Der gcc konvertiert nicht.
... er warnt aber, wenn man ihn lieb drum bittet. -Wall liefert eine
entsprechende Warnung.
Der entscheidende Punkt waere, dass das gar kein 'C-Programmtext'
ist, denn er hat keine durch die C-Norm definierte Bedeutung. Das er
aufgrund von oberflaechlichen Aehnlichkeiten fuer einen gehalten
werden koennte, waere ein anderer Aspekt.
Um ein altes Beispiel von mir wiederzuverwerten: In natuerlichen
Sprachen gibt es sogenannte 'unikale Morpheme', das sind
bedeutungstragende Wortteile, die ausschliesslich in einer Weise mit
anderen Morphemen kombiniert werden koennen. Ein Beispiel fuer ein
unikales Morphem in Deutschen waere 'schorn', welches ausschliesslich
in der Kombination 'schorn-stein' vorkommen kann. Jemand, der des
Deutschen nicht ausreichend maechtig ist, koennte jetzt folgendes
annehmen: Es gibt das Wort 'Schornstein' und das Wort
'Backstein'. Weiterhin gibt es das Wort 'Backofen'. Ergo: 'Schornofen'
bezeichnet den Ofen, der zu einem bestimmten Schornstein gehoert.
Das stimmt zwar nicht, aber das kann man nicht aus den 'formellen'
Wortbildungsregeln ableiten, sondern nur durch Kenntnis der Semantik.