3 Stimmen

Erläuterung der Ausgabe von C-Code

Ich bin auf diesen Code gestoßen:

#include<stdio.h>
void main()
{
    int x;
    float t;
    scanf("%f",&t);
    printf("%d\n",t);
    x=90;
    printf("%f\n",x);
    {
        x=1;
        printf("%f\n",x);
        {
            x=30;
            printf("%f\n",x);
        }
        printf("%f\n",x);
    }
    printf("%f\n",x);
}  

Bei einem Blick darauf dachte ich, es handele sich um eine undefinierte Leistung, wie sie in Normen angegeben ist:

Eine Warnung: printf verwendet sein erstes Argument folgen und welchen Typ sie haben. Es wird verwirrt, und Sie erhalten falsche Antworten, wenn nicht genügend Argumente vorhanden sind oder wenn sie vom falschen Typs sind.

Aber die Ausgabe ließ mich diese Frage nicht unbesehen lassen.
(die eingegebene Zahl ist 23).

23 
0
23.000000
23.000000
23.000000
23.000000
23.000000

Warum immer 23.00000? Was versucht der Compiler hier eigentlich zu tun? Anstatt mit dem Wert herumzuspielen, der unter x warum wird dann der Wert von t ? Hat es irgendeine Erklärung, denn es scheint etwas definiert über diese undefinierte Ausgabe (Wortspiel beabsichtigt).

Edita:

Ich verwende den gcc-Compiler auf einem 32-Bit-Rechner.

10voto

Cubbi Punkte 44766

Das Verhalten des Programms ist undefiniert, der Compiler darf alles tun, was er will.

Allerdings kann ich dieses Verhalten auf meinem System reproduzieren, und ein Blick auf die Assembly-Ausgabe zeigt, was passiert:

printf("%d\n",t); beginnt mit dem Laden des Gleitkommawertes aus t in das CPU-Register %xmm0 das auf meiner Plattform verwendet wird, um Fließkomma-Argumente an Funktionen zu übergeben. Auf dieses Register wird nicht durch diesen Aufruf von printf() da es stattdessen nach einer Ganzzahleneingabe sucht.

Keiner der nachfolgenden Aufrufe von printf() laden Sie beliebige Werte in %xmm0 da Sie keine Gleitkommawerte an printf oder eine andere Funktion übergeben. Aber wenn jede printf Begegnungen %f in seinem Formatstring, liest er aus %xmm0 die noch Folgendes enthält 23.0

Assembler-Ausgabe aus CLang, unter Verwendung eines einfacheren Programms mit float t = 23.0;

.LCPI0_0:
    .quad   4627167142146473984     # double 2.300000e+01
...
    movl    $.L.str, %edi          # .L.str is "%d\n"
    movsd   .LCPI0_0(%rip), %xmm0  # 23.0 stored in xmm0 here
    movb    $1, %al
    callq   printf                 # this printf will print %esi

    movl    $90, %esi              # 90 stored in %esi here
    movl    $.L.str1, %edi         # .L.str1 is "%f\n"
    xorb    %al, %al
    callq   printf                 # but this printf will print %xmm0

1voto

antlersoft Punkte 14491

Wenn Sie wirklich wissen wollen, was das Verhalten hier hervorruft, müssen Sie sich den Assemblercode ansehen, in den dieser (völlig fehlerhafte) C-Code für Ihren speziellen Compiler und Ihre CPU übersetzt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X