4 Stimmen

"Die Größe der C-Variablen ist maschinenabhängig." Stimmt das wirklich? Zahlen mit und ohne Vorzeichen ;

Mir wurde gesagt, dass C-Typen maschinenabhängig sind. Heute wollte ich das überprüfen.

void legacyTypes()
{
    /* character types */
    char k_char = 'a';

        //Signedness --> signed & unsigned
        signed char k_char_s = 'a';
        unsigned char k_char_u = 'a';

    /* integer types */
    int k_int = 1; /* Same as "signed int" */

        //Signedness --> signed & unsigned
        signed int k_int_s = -2;
        unsigned int k_int_u = 3;

        //Size --> short, _____,  long, long long
        short int k_s_int = 4;
        long int k_l_int = 5;
        long long int k_ll_int = 6;

    /* real number types */
        float k_float = 7;
        double k_double = 8;
}

Ich habe es auf einem 32-Bit-Maschine Verwendung des minGW C-Compilers

_legacyTypes:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $48, %esp
    movb    $97, -1(%ebp)  # char
    movb    $97, -2(%ebp)  # signed char
    movb    $97, -3(%ebp)  # unsigned char
    movl    $1, -8(%ebp)    # int
    movl    $-2, -12(%ebp)# signed int 
    movl    $3, -16(%ebp) # unsigned int
    movw    $4, -18(%ebp) # short int
    movl    $5, -24(%ebp) # long int
    movl    $6, -32(%ebp) # long long int
    movl    $0, -28(%ebp) 
    movl    $0x40e00000, %eax
    movl    %eax, -36(%ebp)
    fldl    LC2
    fstpl   -48(%ebp)
    leave
    ret

Ich habe denselben Code auf 64-Bit-Prozessor (Intel Core 2 Duo) auf GCC (linux)

legacyTypes:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movb    $97, -1(%rbp) # char
    movb    $97, -2(%rbp) # signed char
    movb    $97, -3(%rbp) # unsigned char
    movl    $1, -12(%rbp) # int
    movl    $-2, -16(%rbp)# signed int 
    movl    $3, -20(%rbp) # unsigned int
    movw    $4, -6(%rbp)   # short int
    movq    $5, -32(%rbp) # long int
    movq    $6, -40(%rbp) # long long int
    movl    $0x40e00000, %eax
    movl    %eax, -24(%rbp)
    movabsq $4620693217682128896, %rax
    movq    %rax, -48(%rbp)
    leave
    ret

Beobachtungen

  • char, signed char, unsigned char, int, unsigned int, signed int, short int, unsigned short int, signed short int belegen alle die gleiche Anzahl von Bytes auf 32-Bit und 64-Bit Prozessoren.

  • Die einzige Änderung betrifft die long int & long long int beide belegen 32-Bit auf 32-Bit-Maschinen und 64-Bit auf 64-Bit-Maschinen.

  • Und auch die Zeiger, die 32-Bit auf 32-Bit-CPU & 64-Bit auf 64-Bit-CPU nehmen.

Fragen:

  • Ich kann nicht sagen, dass das, was in den Büchern steht, falsch ist. Aber ich vermisse hier etwas. Was genau bedeutet "Variablentypen sind maschinenabhängig"?
  • Wie Sie sehen können, gibt es keinen Unterschied zwischen Anweisungen für vorzeichenlose und vorzeichenbehaftete Zahlen. Wie kommt es dann, dass der Bereich der Zahlen, die mit beiden adressiert werden können, unterschiedlich ist?
  • Ich habe gelesen Wie kann man die feste Größe von C-Variablentypen auf verschiedenen Rechnern beibehalten? Ich habe weder den Zweck der Frage noch ihre Antworten verstanden. Was ist die Beibehaltung der festen Größe? Sie sind alle gleich groß. Ich habe nicht verstanden, wie diese Antworten die gleiche Größe gewährleisten sollen.

EDIT:

Ist es nicht unmöglich, die gleiche Größe auf verschiedenen Maschinen bereitzustellen? Ich meine, wie kann man dieselbe Zeigergröße auf 64-Bit- und 32-Bit-Maschinen beibehalten?

8voto

Péter Török Punkte 111735

Es gibt noch viel mehr Plattformen, und einige von ihnen sind 16 oder sogar 8 Bit! Auf diesen Plattformen sind die Größenunterschiede zwischen den oben genannten Typen viel größer.

Vorzeichenbehaftete und vorzeichenlose Versionen desselben Basistyps belegen auf jeder Plattform die gleiche Anzahl von Bytes, ihr Zahlenbereich ist jedoch unterschiedlich, da für eine vorzeichenbehaftete Zahl der gleiche Bereich möglicher Werte zwischen dem vorzeichenbehafteten und dem vorzeichenlosen Bereich geteilt wird.

Ein 16-Bit-Int mit Vorzeichen kann z. B. Werte von -32767 (oder -32768 auf vielen Plattformen) bis 32767 haben. Ein vorzeichenloser int der gleichen Größe liegt im Bereich von 0 bis 65535.

Danach verstehen Sie hoffentlich den Sinn der gestellten Frage besser. Wenn Sie ein Programm unter der Annahme schreiben, dass z.B. Ihre vorzeichenbehafteten int-Variablen den Wert 2*10^9 (2 Milliarden) halten können, ist Ihr Programm nicht portabel, da dieser Wert auf einigen Plattformen (16 Bit und darunter) einen Überlauf verursacht, was zu stillen und schwer zu findenden Fehlern führt. So müssen Sie z.B. auf einer 16-Bit-Plattform #define Ihre Ints zu sein long um einen Überlauf zu vermeiden. Dies ist ein einfaches Beispiel, das möglicherweise nicht auf allen Plattformen funktioniert, aber ich hoffe, es vermittelt Ihnen eine grundlegende Vorstellung.

Der Grund für all diese Unterschiede zwischen den Plattformen ist, dass es zu der Zeit, als C standardisiert wurde, bereits viele C-Compiler gab, die auf einer Vielzahl verschiedener Plattformen verwendet wurden, so dass aus Gründen der Abwärtskompatibilität all diese Varianten als gültig akzeptiert werden mussten.

7voto

oefe Punkte 18208

Maschinenabhängig ist nicht ganz exakt. Eigentlich ist es Implementierung definiert . Dies kann vom Compiler, der Maschine, den Compileroptionen usw. abhängen.

Zum Beispiel mit Visual C++, long auch auf 64-Bit-Maschinen 32-Bit sein würde.

4voto

T.J. Crowder Punkte 948310

Was genau bedeutet "Variablentypen sind maschinenabhängig"?

Es bedeutet genau das, was es sagt: Die Größen der meisten integralen C-Typen sind maschinenabhängig (nicht wirklich Maschine so sehr wie Architektur und Compiler). Als ich in den frühen 90er Jahren viel mit C arbeitete, int war meist 16 Bit; jetzt sind es meist 32 Bit. Vor meiner C-Karriere waren es vielleicht noch 8 Bits. Und so weiter.

Offenbar haben die Entwickler des C-Compilers, den Sie für die 64-Bit-Kompilierung verwenden, beschlossen int sollte 32 Bit bleiben. Die Entwickler eines anderen C-Compilers könnten eine andere Wahl treffen.

1voto

Rowland Shaw Punkte 37027

Wenn Sie Ihren Test z.B. auf einem Motorola 68000-Prozessor wiederholen würden, würden Sie andere Ergebnisse erhalten (wobei ein Wort 16 Bit und ein Long 32 Bit beträgt - normalerweise ist ein int ein Wort)

1voto

Jerry Coffin Punkte 452852

Echte Compiler nutzen in der Regel nicht alle von der Norm zugelassenen Variationen aus. Die Anforderungen in der Norm geben nur eine Minimum Bereich für den Typ - 8 Bits für char, 16 Bits für short und int, 32 Bits für long und (in C99) 64 Bits für long long (und jeder Typ in dieser Liste muss einen mindestens so großen Bereich haben wie der vorhergehende Typ).

Für einen echten Compiler ist die Abwärtskompatibilität jedoch fast immer ein wichtiges Ziel. Das bedeutet, dass sie eine starke Motivation haben, so wenig wie möglich zu ändern. Daher gibt es in der Praxis viel mehr Gemeinsamkeiten zwischen Compilern, als der Standard verlangt.

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