printf fügt zusätzliches `FFFFFF` zum Hex-Print aus einem char-Array hinzu [duplicate]

Lesezeit: 4 Minuten

Betrachten Sie den folgenden vereinfachten Code unten. Ich möchte einige binäre Daten/Streams aus einer Datei extrahieren und im Hexadezimalformat auf die Standardausgabe drucken.

Ich habe zusätzliche 3 Bytes 0xFFFFFF. Was ist los? Woher kommen die zusätzlichen Bytes?

Ausgang

in:
        2000FFFFFFAF00690033005A00
out:
        2000FFFFFFAF00690033005A00

Programm.c

#include <stdio.h>
#include <stdlib.h>    

int main(int argc, char** argv) {

    int i;
    char raw[10] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
    FILE *outfile;
    char *buf;

    printf("in:\n\t");
    for( i=0; i<10; i++ )
        printf("%02X", raw[i]);

    outfile = fopen("raw_data.bin", "w+b");

    fwrite(raw, 1, 10, outfile);

    buf = (char *) malloc (32 * sizeof(char));
    fseek(outfile, 0, SEEK_SET);
    fread(buf, 1, 10, outfile);

    printf("\nout:\n\t");
    for( i=0; i<10; i++ )
        printf("%02X", buf[i]);

    printf("\n");

    fclose(outfile);
    return 0;
}

  • Verwenden unsigned char Weil 0xAF > CHAR_MAX. Schmucklos char ist für Saiten.

    – cremnr

    27. Juni 2015 um 16:01 Uhr


  • @cremno es hängt tatsächlich vom System ab, einfach char kann signiert oder unsigniert sein.

    – Ryan Haining

    27. Juni 2015 um 16:04 Uhr

  • Standardwarnung: Nicht werfen void * (z. B. gegeben von malloc()) zu anderen Zeigern! Ebenfalls: sizeof(char) wird sich nie von unterscheiden 1denn das ist es, was der Standard nachgeben soll!

    – zu ehrlich für diese Seite

    27. Juni 2015 um 16:57 Uhr


  • Wenn das Ändern des Typs keine Option ist, werfen Sie ihn einfach: printf("%02X", (unsigned char)buf[i]);

    – KrisWebDev

    14. Juni 2016 um 18:46 Uhr

  • Warum gibt printf beim Drucken von hex nicht nur ein Byte aus?

    – phuklv

    4. November 2016 um 9:22 Uhr

Benutzer-Avatar
Ryan Haining

Erweiterung anmelden. Ihr Compiler implementiert char Als ein signed char. Wenn Sie die Zeichen an übergeben printf Sie alle werden während ihrer Beförderung zu Sign Extended ints. Wenn das erste Bit eine 0 ist, spielt dies keine Rolle, da es mit erweitert wird 0s.

0xAF in binär ist 10101111 Da das erste Bit a ist 1beim Übergeben an printf es wird mit allen erweitert 1s in der Konvertierung zu int Ich mach das 11111111111111111111111110101111der Hex-Wert, den Sie haben.

Lösung: Verwenden unsigned char (Anstatt von char), um zu verhindern, dass die Vorzeichenerweiterung im Anruf auftritt

const unsigned char raw[] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};

Alle diese Werte in Ihrem ursprünglichen Beispiel werden vorzeichenerweitert, es ist nur so 0xAF ist der einzige mit a 1 im ersten Bit.

Ein weiteres einfacheres Beispiel für dasselbe Verhalten (Live-Link):

signed char c = 0xAF; // probably gives an overflow warning
int i = c; // extra 24 bits are all 1
assert( i == 0xFFFFFFAF );

Benutzer-Avatar
Jens

Das liegt daran, dass 0xAF bei der Konvertierung von einem vorzeichenbehafteten Zeichen in eine vorzeichenbehaftete Ganzzahl negativ ist (es ist vorzeichenerweitert) und die %02X format ist für vorzeichenlose Argumente und gibt den konvertierten Wert als aus FFFFFFAF.

Die zusätzlichen Zeichen erscheinen, weil printf %x Wille noch nie Ziffern von einem Wert stillschweigend abschneiden. Werte, die nicht negativ sind, werden ebenfalls vorzeichenerweitert, aber das fügt nur Nullbits hinzu und der Wert passt in 2 Hexadezimalziffern, also printf %02 kann mit einer zweistelligen Ausgabe auskommen.

Beachten Sie, dass es 2 C-Dialekte gibt: einen, wo Plain char signiert ist, und eine, bei der es unsigniert ist. Bei dir ist es unterschrieben. Sie können es mit einer Option ändern, z. B. gcc- und clang-Unterstützung -funsigned-char und -fsigned-char.

  • Das Ändern der Vorzeichen von char ist keine dauerhafte Lösung …

    – Antti Haapala – Слава Україні

    9. Mai 2016 um 12:14 Uhr

Benutzer-Avatar
Grzegorz Szpetkowski

Das printf() ist ein variadisch Funktion und ihre zusätzlichen Argumente (entsprechend mit ... Teil seines Prototyps) unterliegen Standardargument-Promotionsdaher char befördert wird int.

Wie dein char hat unterschrieben1, Zweierkomplement Darstellung wird das höchstwertige Bit auf eins gesetzt 0xAF Element. Während der Heraufstufung wird ein vorzeichenbehaftetes Bit weitergegeben, was zur Folge hat 0xFFFFFFAF von int Typ, wie vermutlich sizeof(int) = 4 bei deiner Umsetzung.

Übrigens rufst du an undefiniertes Verhaltenseit %X Der Formatbezeichner sollte für das Objekt des Typs verwendet werden unsigned int oder zumindest für int mit MSB, das nicht gesetzt ist (dies ist eine übliche, weithin akzeptierte Praxis).

Wie vorgeschlagen, können Sie die Verwendung von eindeutig in Betracht ziehen unsigned char Typ.


1) Die Implementierung kann zwischen signierter und unsignierter Darstellung wählen char. Das ist eher üblich char ist signiert, aber Sie können es nicht für jeden anderen Compiler auf dem Planeten als selbstverständlich ansehen. Einige von ihnen erlauben möglicherweise die Wahl zwischen diesen beiden Modi, wie in Jens Antwort erwähnt.

1363750cookie-checkprintf fügt zusätzliches `FFFFFF` zum Hex-Print aus einem char-Array hinzu [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy