Cum se convertește un șir hexazecimal într-un șir binar în C (Programare, C, Binar, Hexagonal)

Midhun MP a intrebat.

Am un fișier text cu valori hexazecimale. Acum am nevoie să convertesc valoarea hexazecimală în binar și trebuie să o salvez într-un alt fișier.Dar nu știu cum să convertesc valoarea hexazecimală într-un șir binar!Vă rog să mă ajutați…

Comentarii

  • Puteți încerca astfel: johnsantic.com/comp/htoi.html –  > Por Andrija Sucevic.
  • Temă pentru acasă? Și sunt sigur că nu te referi la valori, ci la reprezentări: valorile sunt aceleași indiferent de modul în care sunt reprezentate. –  > Por pmg.
  • @pmg:da, făceam un fel de temă pentru acasă. De fapt am convertit un fișier imagine în fișier hexazecimal. Acum trebuie să creez o imagine din acel fișier hexazecimal. –  > Por Midhun MP.
  • @StanlyMoses: Citiți cu atenție întrebările înainte de a le închide ca fiind duplicate, aceasta întreabă cum să convertească hexagonal în binar cealaltă întreabă cum să convertească binar în hexagonal. –  > Por Midhun MP.
8 răspunsuri
Mario
const char input[] = "..."; // the value to be converted
char res[9]; // the length of the output string has to be n+1 where n is the number of binary digits to show, in this case 8
res[8] = '';
int t = 128; // set this to s^(n-1) where n is the number of binary digits to show, in this case 8
int v = strtol(input, 0, 16); // convert the hex value to a number

while(t) // loop till we're done
{
    strcat(res, t < v ? "1" : "0");
    if(t < v)
        v -= t;
    t /= 2;
}
// res now contains the binary representation of the number

Ca o alternativă (asta presupunând că nu există un prefix ca în "0x3A"):

const char binary[16][5] = {"0000", "0001", "0010", "0011", "0100", ...};
const char digits = "0123456789abcdef";

const char input[] = "..." // input value
char res[1024];
res[0] = '';
int p = 0;

while(input[p])
{
    const char *v = strchr(digits, tolower(input[p++]));
    if (v)
        strcat(res, binary[v - digits]);
}
// res now contains the binary representation of the number

Comentarii

  • @OuwenHuang Sunteți sigur că dvs. digits este corect? Sau de unde ai această eroare? –  > Por Mario.
  • Am nevoie de ajutor aici. Am încercat versiunea 2 a răspunsului textual și strcat nu populează deloc matricea res, ci rămâne la pe tot parcursul. –  > Por sce.
  • @sce greu de ghicit. Doar creați-vă propria întrebare și legați acest răspuns pentru referință. –  > Por Mario.
  • Cum anume ar trebui să funcționeze a 2-a soluție? v[0] este caracterul, sau numeric valoarea ascii, deci dacă v[0] = f, atunci indicele în binar este 102, nu 15. Cel puțin așa pare a fi cazul, pentru că la mine se defectează pe acea linie. –  > Por krb686.
  • Nu am reușit să fac să funcționeze cea de-a doua soluție, dar ceea ce a funcționat a fost long v = strtol({input[p++], 0}, NULL, 16); strcat(res, binary[v]); –  > Por krb686.
Armen Tsirunyan

Este destul de ușor, într-adevăr, pentru că traducerea merge cifră cu cifră.

0 - 0000
1 - 0001
2 - 0010
3 - 0011
4 - 0100
5 - 0101
6 - 0110
7 - 0111
8 - 1000
9 - 1001
A - 1010
B - 1011
C - 1100
D - 1101
E - 1110
F - 1111

Deci, de exemplu, numărul hexagonal FE2F8 va fi 11111110001011111000 în binar

josch

Există mai multe modalități de a rezolva această întrebare care utilizează unele aritmetici pentru a converti din intervalele de caractere ascii 0-9 și a-f (sau A-F) în binar. Am vrut să găsesc o soluție care să folosească doar un tabel de căutare și să o compar cu o soluție care folosește în schimb aritmetica. În mod ciudat, niciunul dintre răspunsurile de mai sus nu implementează o soluție pur aritmetică, iar unele răspunsuri chiar presupun că „convertirea în binar” înseamnă convertirea într-un șir ascii de caractere „0” și „1”.

Să facem mai întâi câteva configurări. În primul rând, dorim să avem toate datele de test în memorie, astfel încât să evităm ca I/O pe disc să influențeze testul. Iată cum creez un antet cu o matrice de caractere „testdata” de 104857600 octeți, adică aproximativ 105 MB. Deoarece întrebarea a fost cum să convertim fișiere, implementarea noastră ar trebui să fie rapidă pe date mari.

$ { printf "char *testdata =
"; cat /dev/urandom 
    | tr -d -c "0123456789abcdefABCDEF" 
    | dd count=100 iflag=fullblock bs=1M; printf "
;
" } > testdata.h

În continuare, creăm tabelele de căutare. Văd două moduri posibile de a rezolva acest lucru cu un tabel de căutare. Fie tabela de căutare mapează caracterele ascii hexagonale individuale în jumătăți de octeți, fie mapează două caractere hexagonale într-un octet întreg. În primul caz, tabelul de căutare trebuie să aibă 256 de intrări. În cel de-al doilea caz, tabelul de căutare trebuie să aibă 256*256=65536 de intrări. Putem reduce dimensiunea acestuia din urmă prin faptul că primul bit al primului octet nu va fi niciodată utilizat. Astfel, avem nevoie doar de un tabel de căutare de 128*256=32768 intrări. Deoarece această soluție necesită, de asemenea, o etapă suplimentară de calcul (aplicarea unei măști de biți), le vom compara pe ambele. Vom obține următoarele cazuri de testare:

  1. soluția aritmetică
  2. tabel de căutare cu 256 de intrări
  3. tabel de căutare cu 32768 intrări
  4. 65536 intrări tabel de căutare

Prima tabelă de căutare este ușor de generat cu ajutorul unui program python:

#!/usr/bin/env python

import sys,struct

sys.stdout.write("unsigned char base16_decoding_table1[256] = {
")

for i in xrange(256):
    try:
        j = str(int(chr(i), 16))
    except:
        j = '0'
    sys.stdout.write(j+',')
sys.stdout.write("};
")

sys.stdout.write("
")

l = 128*256*["0"]

for a in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
    for b in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
        l[struct.unpack("<H", a+b)[0]] = str(int(a+b, 16))

line = "unsigned char base16_decoding_table2[%d] = {"%(128*256)

for e in l:
    line += e+","
    if len(line) > 70:
        sys.stdout.write(line+"
")
        line = ""
sys.stdout.write(line+"};
")

sys.stdout.write("
")

l = 256*256*["0"]

for a in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
    for b in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
        l[struct.unpack("<H", a+b)[0]] = str(int(a+b, 16))

line = "unsigned char base16_decoding_table3[%d] = {"%(256*256)

for e in l:
    line += e+","
    if len(line) > 70:
        sys.stdout.write(line+"
")
        line = ""
sys.stdout.write(line+"};
")

Și apoi:

python gen.py > base16_decoding_table.h

Acum putem scrie niște cod C pentru a testa.

#include <stdio.h>
#include <time.h>
#include <inttypes.h>

#include "testdata.h"
#include "base16_decoding_table.h"

#define TESTDATALEN 104857600

/* the resulting binary string is half the size of the input hex string
 * because every two hex characters map to one byte */
unsigned char result[TESTDATALEN/2];

void test1()
{
    size_t i;
    char cur;
    unsigned char val;
    for (i = 0; i < TESTDATALEN; i++) {
        cur = testdata[i];
        if (cur >= 97) {
            val = cur - 97 + 10;
        } else if (cur >= 65) {
            val = cur - 65 + 10;
        } else {
            val = cur - 48;
        }
        /* even characters are the first half, odd characters the second half
         * of the current output byte */
        if (i%2 == 0) {
            result[i/2] = val << 4;
        } else {
            result[i/2] |= val;
        }
    }
}

void test2()
{
    size_t i;
    char cur;
    unsigned char val;
    for (i = 0; i < TESTDATALEN; i++) {
        cur = testdata[i];
        val = base16_decoding_table1[(int)cur];
        /* even characters are the first half, odd characters the second half
         * of the current output byte */
        if (i%2 == 0) {
            result[i/2] = val << 4;
        } else {
            result[i/2] |= val;
        }
    }
}

void test3()
{
    size_t i;
    uint16_t *cur;
    unsigned char val;
    for (i = 0; i < TESTDATALEN; i+=2) {
        cur = (uint16_t*)(testdata+i);
        // apply bitmask to make sure that the first bit is zero
        val = base16_decoding_table2[*cur & 0x7fff];
        result[i/2] = val;
    }
}

void test4()
{
    size_t i;
    uint16_t *cur;
    unsigned char val;
    for (i = 0; i < TESTDATALEN; i+=2) {
        cur = (uint16_t*)(testdata+i);
        val = base16_decoding_table3[*cur];
        result[i/2] = val;
    }
}

#define NUMTESTS 1000

int main() {
    struct timespec before, after;
    unsigned long long checksum;
    int i;
    double elapsed;

    clock_gettime(CLOCK_MONOTONIC, &before);
    for (i = 0; i < NUMTESTS; i++) {
        test1();
    }
    clock_gettime(CLOCK_MONOTONIC, &after);

    checksum = 0;
    for (i = 0; i < TESTDATALEN/2; i++) {
        checksum += result[i];
    }
    printf("checksum: %llu
", checksum);
    elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
    printf("arithmetic solution took %f seconds
", elapsed);

    clock_gettime(CLOCK_MONOTONIC, &before);
    for (i = 0; i < NUMTESTS; i++) {
        test2();
    }
    clock_gettime(CLOCK_MONOTONIC, &after);

    checksum = 0;
    for (i = 0; i < TESTDATALEN/2; i++) {
        checksum += result[i];
    }
    printf("checksum: %llu
", checksum);
    elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
    printf("256 entries table took %f seconds
", elapsed);

    clock_gettime(CLOCK_MONOTONIC, &before);
    for (i = 0; i < NUMTESTS; i++) {
        test3();
    }
    clock_gettime(CLOCK_MONOTONIC, &after);

    checksum = 0;
    for (i = 0; i < TESTDATALEN/2; i++) {
        checksum += result[i];
    }
    printf("checksum: %llu
", checksum);
    elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
    printf("32768 entries table took %f seconds
", elapsed);

    clock_gettime(CLOCK_MONOTONIC, &before);
    for (i = 0; i < NUMTESTS; i++) {
        test4();
    }
    clock_gettime(CLOCK_MONOTONIC, &after);

    checksum = 0;
    for (i = 0; i < TESTDATALEN/2; i++) {
        checksum += result[i];
    }
    printf("checksum: %llu
", checksum);
    elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
    printf("65536 entries table took %f seconds
", elapsed);

    return 0;
}

Să compilăm:

$ gcc -O3 -g -Wall -Wextra test.c

Și să îl rulăm:

$ ./a.out

Rezultatul:

  1. soluția aritmetică: 437.17 s
  2. tabel de căutare cu 256 de intrări: 117.80 s
  3. 32768 intrări în tabelul de căutare: 52.33 s
  4. 65536 intrări tabel de căutare: 44.66 s

Astfel, putem concluziona că tabelele de căutare bat oricând soluțiile aritmetice și că risipa de memorie pentru tabele de căutare mai mari ar putea merita timpul de execuție suplimentar.

Comentarii

  • Cum este posibil ca un număr mai mare de intrări să aibă un timp de analiză comparativă mai mic? –  > Por Zimano.
  • @Zimano pentru că o tabelă de căutare mai mare înseamnă mai multe căutări și mai puține operații aritmetice –  > Por josch.
  • Ooh, înțeleg. Asta e destul de interesant, de fapt, mulțumesc! –  > Por Zimano.
Will
void hex_binary(char * res){
char binary[16][5] = {"0000", "0001", "0010", "0011", "0100", "0101","0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110","1111"};
char digits [] = "0123456789abcdef";

const char input[] = "a9e6"; // input value
res[0] = '';
int p = 0;
int value =0;
    while(input[p])
    {
        const char *v = strchr(digits, tolower(input[p]));
        if(v[0]>96){
            value=v[0]-87;
        }
        else{
            value=v[0]-48;
        }
        if (v){
            strcat(res, binary[value]);
        }
        p++;
    }
    printf("Res:%s
", res);
}

Comentarii

  • Versiunea compilată a răspunsului 1 –  > Por Will.
PSkocik
void printBin(unsigned int num){
  char str[sizeof(num)*8];
  char *p = str;
  for(*p='0'; num; num/=2) { *p++='0'+num%2; } //store remainders
  for(--p; p>=str; putchar(*p--)) {;}          //print remainders in reverse
  putchar('
');
}

Manel

Asta e funcția mea de a converti HEX în BIN, octet cu octet.

void HexToBin(char hex_number, char* bit_number) {
    int max = 128;
    for(int i = 7 ; i >-1 ; i--){
        bit_number [i] = (hex_number & max ) ? 1 : 0;
        max >>=1;
    }
}

Și apelul la funcție:

void main (void){

    char hex_number = 0x6E; //0110 1110
    char bit_number[8]={0,0,0,0,0,0,0,0};
    HexToBin(hex_number,bit_number);

    for(int i = 7 ; i >-1 ; i--)
        printf("%d",bit_number[i]);

    printf("
");
    system("pause");
}

Și iată și răspunsul MSDOS:

01101110

Press a key to continue . . .

Destul de ușor!

Comentarii

  • Aceasta tipărește unu și zero în ascii. Cum convertește acest lucru orice hexagonal în reprezentarea lor binară? –  > Por josch.
Pete Wilson

Cea mai rapidă și mai simplă metodă este să citiți fișierul hexazecimal și, pentru fiecare caracter („0” până la „F”) citit, să faceți o căutare în tabel a valorii binare echivalente (de la 0 la 15). Există, ca întotdeauna, modalități mai elegante, dar aceasta este foarte simplă, poate ceva de genul:

switch (charval) {
  case '0': binval = 0;
  case '1': binval = 1;
  case '2': binval = 2;
  case '3': binval = 3;
   ....
  case 'a': binval = 10;
  case 'b': binval = 11;
  case 'A': binval = 10;
  case 'B': binval = 11;
  ....
  case 'f':  binval = 15;
  case 'F':  binval = 15;
  default:   binval = -1;  // error case
}

Acum trebuie să folosiți decalaje și IOR/ADD pentru a construi cuvinte de dimensiunea dorită din aceste valori binare individuale pe 4 biți.

Comentarii

  • În acest fel, veți obține valoarea numerică a unei cifre hexagonale, dar nu veți obține reprezentarea binară. De asemenea, pentru a face o astfel de căutare, aș folosi fie un șir fix (0123456789abcdef) și apoi să obțineți valoarea unei cifre utilizând strchr() fie aș folosi o matrice char [256] și aș folosi caracterul/digita ca index. În acest fel, ați putea la fel de bine să folosiți reprezentarea binară a cifrelor ca valori și să săriți peste conversia suplimentară. –  > Por Mario.
  • Aceasta nu este o căutare în tabel. O căutare în tabel ar fi O(1), dar soluția dvs. utilizează căutări care sunt O(N). –  > Por josch.
Iftekhar UiU
#include <stdio.h>

int main()
{
    long int binaryNumber,
             hexadecimalNumber = 0,
             j = 1,
             remainder;

    printf("Enter any number any binary number: ");
    scanf("%ld", &binaryNumber);

    while(binaryNumber != 0) {
        remainder = binaryNumber % 10;
        hexadecimalNumber = hexadecimalNumber + remainder * j;
        j = j * 2;
        binaryNumber = binaryNumber / 10;
    }
    printf("Equivalent hexadecimal value: %X", hexadecimalNumber);
    return 0;
}

user447688

Comentarii

  • Deși acest cod poate răspunde la întrebare, furnizarea unui context suplimentar cu privire la motivul și/sau modul în care acest cod răspunde la întrebare îmbunătățește valoarea sa pe termen lung. –  > Por JAL.