Ik probeer een regel met tekens in te lezen en vervolgens het hexadecimale equivalent van de tekens af te drukken.
Als ik bijvoorbeeld een tekenreeks heb die "0xc0 0xc0 abc123"
is, waarbij de eerste 2 tekens c0
in hex zijn en de overige tekens abc123
in ASCII, dan zou ik
. moeten krijgen
c0 c0 61 62 63 31 32 33
Echter, printf
met %x
geeft me
ffffffc0 ffffffc0 61 62 63 31 32 33
Hoe krijg ik de output die ik wil zonder de "ffffff"
? En waarom heeft alleen c0 (en 80) de ffffff
, maar niet de andere karakters?
Antwoord 1, autoriteit 100%
Je ziet de ffffff
omdat char
is ondertekend op je systeem. In C zullen vararg-functies zoals printf
alle gehele getallen kleiner dan int
promoveren naar int
. Aangezien char
een geheel getal is (8-bits geheel getal met teken in jouw geval), worden je tekens gepromoveerd tot int
via tekenextensie.
Aangezien c0
en 80
een leidende 1-bit hebben (en negatief zijn als een 8-bit integer), worden ze teken-uitgebreid terwijl de anderen in uw voorbeeld niet.
char int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
Hier is een oplossing:
char ch = 0xC0;
printf("%x", ch & 0xff);
Dit maskeert de bovenste bits en behoudt alleen de onderste 8 bits die je wilt.
Antwoord 2, autoriteit 45%
Er is inderdaad typeconversie naar int.
U kunt ook typen om char te forceren door de %hhx-specificatie te gebruiken.
printf("%hhX", a);
In de meeste gevallen wil je ook de minimumlengte instellen om het tweede teken met nullen te vullen:
printf("%02hhX", a);
ISO/IEC 9899:201x zegt:
7 De lengte-aanpassers en hun betekenis zijn:
hh Specificeert dat een volgende conversiespecificatie d, i, o, u, x of X van toepassing is op a
ondertekend char of unsigned char argument (het argument zal hebben
gepromoot volgens de integer-promoties, maar de waarde ervan zal zijn
geconverteerd naar ondertekende char of niet-ondertekende char voor het afdrukken); of dat
een volgende
Antwoord 3, autoriteit 21%
U kunt een niet-ondertekend teken maken:
unsigned char c = 0xc5;
Afdrukken geeft C5
en niet ffffffc5
.
Alleen de tekens groter dan 127 worden afgedrukt met de ffffff
omdat ze negatief zijn (teken is ondertekend).
Of je kunt de char
casten tijdens het printen:
char c = 0xc5;
printf("%x", (unsigned char)c);
Antwoord 4, autoriteit 10%
Je kunt hh
gebruiken om printf
dat het argument een teken zonder teken is. Gebruik 0
om nul opvulling te krijgen en 2
om de breedte in te stellen op 2. X
of X
voor kleine letters/hoofdletters hexadecimale tekens.
uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"
Bewerken: als lezers zich zorgen maken over de bewering van 2501 dat dit op de een of andere manier niet de ‘juiste’ formaatspecificaties zijn, raad ik aan de printf
linkopnieuw. Specifiek:
Hoewel %c een int-argument verwacht, is het veilig om een char door te geven vanwege de integer-promotie die plaatsvindt wanneer een variadische functie wordt aangeroepen.
De juiste conversiespecificaties voor de tekentypen met vaste breedte (int8_t, enz.) zijn gedefinieerd in de kop
<cinttypes>
(C++) of<inttypes.h>
(C) (hoewel PRIdMAX, PRIuMAX, enz. synoniem is met %jd, %ju, enz.).
Wat betreft zijn punt over ondertekend versus niet-ondertekend, in dit geval maakt het niet uit, omdat de waarden altijd positief moeten zijn en gemakkelijk in een ondertekend int moeten passen. Er is sowieso geen ondertekende hexadeximale formaatspecificatie.
Bewerk 2: (“when-to-admit-you’re-wrong” editie):
Als je de eigenlijke C11-standaardop pagina 311 (329 van de PDF) vindt u:
hh: Specificeert dat een volgende
d
,i
,o
,u
,X
, ofX
conversiespecificatie is van toepassing op eensigned char
ofunsigned char
argument (het argument zal gepromoot zijn volgens de integer-promoties , maar de waarde ervan wordt geconverteerd naarsigned char
ofunsigned char
voordat het wordt afgedrukt); of dat een volgenden
-conversiespecificatie van toepassing is op een aanwijzer naar eensigned char
-argument.
Antwoord 5, autoriteit 9%
U slaat waarschijnlijk de waarde 0xc0 op in een char
variabele, wat waarschijnlijk een ondertekend type is, en uw waarde is negatief (meest significante bitset). Vervolgens wordt het tijdens het afdrukken geconverteerd naar int
en om de semantische equivalentie te behouden, vult de compiler de extra bytes in met 0xff, zodat de negatieve int
hetzelfde numerieke waarde van uw negatieve char
. Om dit op te lossen, cast gewoon naar unsigned char
tijdens het afdrukken:
printf("%x", (unsigned char)variable);
Antwoord 6
U drukt waarschijnlijk af vanuit een ondertekende char-array. Druk af vanuit een niet-ondertekende char-array of maskeer de waarde met 0xff: b.v. ar[i] & 0xFF. De c0-waarden krijgen een tekenverlenging omdat de hoge (teken)bit is ingesteld.
Antwoord 7
Probeer zoiets als dit:
int main()
{
printf("%x %x %x %x %x %x %x %x\n",
0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}
Wat dit oplevert:
$ ./foo
c0 c0 61 62 63 31 32 33