web-dev-qa-db-fra.com

Comment imprimer des octets au format hexadécimal?

Je sais qu'en C #, vous pouvez utiliser la méthode String.Format. Mais comment faites-vous cela en C++? Existe-t-il une fonction qui me permet de convertir un octet en Hex? Juste besoin de convertir une donnée longue de 8 octets en Hex, comment puis-je le faire?

25
Danny

Eh bien, vous pouvez convertir un octet (caractère non signé) à la fois en tableau tel que

char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
    sprintf(&buffer[2*j], "%02X", data[j]);
28
bentech

Si vous souhaitez utiliser des flux C++ plutôt que des fonctions C, vous pouvez effectuer les opérations suivantes:

    int ar[] = { 20, 30, 40, 50, 60, 70, 80, 90 };
    const int siz_ar = sizeof(ar) / sizeof(int);

    for (int i = 0; i < siz_ar; ++i)
        cout << ar[i] << " ";
    cout << endl;

    for (int i = 0; i < siz_ar; ++i)
        cout << hex << setfill('0') << setw(2) << ar[i] << " ";
    cout << endl;

Très simple.

Sortie:

20 30 40 50 60 70 80 90
14 1e 28 32 3c 46 50 5a 
55
Component 10

C:

static void print_buf(const char *title, const unsigned char *buf, size_t buf_len)
{
    size_t i = 0;
    fprintf(stdout, "%s\n", title);
    for(i = 0; i < buf_len; ++i)
    fprintf(stdout, "%02X%s", buf[i],
             ( i + 1 ) % 16 == 0 ? "\r\n" : " " );

}

C++:

void print_bytes(std::ostream& out, const char *title, const unsigned char *data, size_t dataLen, bool format = true) {
    out << title << std::endl;
    out << std::setfill('0');
    for(size_t i = 0; i < dataLen; ++i) {
        out << std::hex << std::setw(2) << (int)data[i];
        if (format) {
            out << (((i + 1) % 16 == 0) ? "\n" : " ");
        }
    }
    out << std::endl;
}
12
user1763487

Imprimer des structures arbitraires en C++ moderne

Jusqu'à présent, toutes les réponses vous indiquent uniquement comment imprimer un tableau d'entiers, mais nous pouvons également imprimer n'importe quelle structure arbitraire, étant donné que nous connaissons sa taille. L'exemple ci-dessous crée une telle structure et itère un pointeur sur ses octets, en les imprimant dans la sortie:

#include <iostream>
#include <iomanip>
#include <cstring>

using std::cout;
using std::endl;
using std::hex;
using std::setfill;
using std::setw;

using u64 = unsigned long long;
using u16 = unsigned short;
using f64 = double;

struct Header {
    u16 version;
    u16 msgSize;
};

struct Example {
    Header header;
    u64 someId;
    u64 anotherId;
    bool isFoo;
    bool isBar;
    f64 floatingPointValue;
};

int main () {
    Example example;
    // fill with zeros so padding regions don't contain garbage
    memset(&example, 0, sizeof(Example));
    example.header.version = 5;
    example.header.msgSize = sizeof(Example) - sizeof(Header);
    example.someId = 0x1234;
    example.anotherId = 0x5678;
    example.isFoo = true;
    example.isBar = true;
    example.floatingPointValue = 1.1;

    cout << hex << setfill('0');  // needs to be set only once
    auto *ptr = reinterpret_cast<unsigned char *>(&example);
    for (int i = 0; i < sizeof(Example); i++, ptr++) {
        if (i % sizeof(u64) == 0) {
            cout << endl;
        }
        cout << setw(2) << static_cast<unsigned>(*ptr) << " ";
    }

    return 0;
}

Et voici la sortie:

05 00 24 00 00 00 00 00 
34 12 00 00 00 00 00 00 
78 56 00 00 00 00 00 00 
01 01 00 00 00 00 00 00 
9a 99 99 99 99 99 f1 3f

Notez que cet exemple illustre également alignement de la mémoire working. Nous voyons version occuper 2 octets (05 00), suivi de msgSize avec encore 2 octets (24 00) puis 4 octets de remplissage, après quoi vient someId (34 12 00 00 00 00 00 00) et anotherId (78 56 00 00 00 00 00 00). Ensuite, isFoo, qui occupe 1 octet (01) et isBar, un autre octet (01), suivi de 6 octets de remplissage, se terminant par la représentation standard IEEE 754 du champ double floatingPointValue.

Notez également que toutes les valeurs sont représentées par little endian (les octets les moins significatifs arrivent en premier), car ils ont été compilés et exécutés sur une plate-forme Intel.

4
Lucio Paiva

Ceci est une version modifiée de la méthode Nibble to Hex

void hexArrayToStr(unsigned char* info, unsigned int infoLength, char **buffer) {
    const char* pszNibbleToHex = {"0123456789ABCDEF"};
    int nNibble, i;
    if (infoLength > 0) {
        if (info != NULL) {
            *buffer = (char *) malloc((infoLength * 2) + 1);
            buffer[0][(infoLength * 2)] = 0;
            for (i = 0; i < infoLength; i++) {
                nNibble = info[i] >> 4;
                buffer[0][2 * i] = pszNibbleToHex[nNibble];
                nNibble = info[i] & 0x0F;
                buffer[0][2 * i + 1] = pszNibbleToHex[nNibble];
            }
        } else {
            *buffer = NULL;
        }
    } else {
        *buffer = NULL;
    }
}
3
Mohamed Saad

Je ne connais pas de meilleur moyen que:

unsigned char byData[xxx]; 

int nLength = sizeof(byData) * 2;
char *pBuffer = new char[nLength + 1];
pBuffer[nLength] = 0;
for (int i = 0; i < sizeof(byData); i++)
{
    sprintf(pBuffer[2 * i], "%02X", byData[i]);
}

Vous pouvez l'accélérer en utilisant une méthode Nibble to Hex

unsigned char byData[xxx];

const char szNibbleToHex = { "0123456789ABCDEF" };

int nLength = sizeof(byData) * 2;
char *pBuffer = new char[nLength + 1];
pBuffer[nLength] = 0;
for (int i = 0; i < sizeof(byData); i++)
{
    // divide by 16
    int nNibble = byData[i] >> 4;
    pBuffer[2 * i]  = pszNibbleToHex[nNibble];

    nNibble = byData[i] & 0x0F;
    pBuffer[2 * i + 1]  = pszNibbleToHex[nNibble];

}
2
Rick Murtagh

Utiliser les flux C++ et restaurer l'état par la suite

Ceci est une variation de Comment imprimer des octets au format hexadécimal? mais:

main.cpp

#include <iomanip>
#include <iostream>

int main() {
    int array[] = {0, 0x8, 0x10, 0x18};
    constexpr size_t size = sizeof(array) / sizeof(array[0]);

    // Sanity check decimal print.
    for (size_t i = 0; i < size; ++i)
        std::cout << array[i] << " ";
    std::cout << std::endl;

    // Hex print and restore default afterwards.
    std::ios cout_state(nullptr);
    cout_state.copyfmt(std::cout);
    std::cout << std::hex << std::setfill('0') << std::setw(2);
    for (size_t i = 0; i < size; ++i)
        std::cout << array[i] << " ";
    std::cout << std::endl;
    std::cout.copyfmt(cout_state);

    // Check that cout state was restored.
    for (size_t i = 0; i < size; ++i)
        std::cout << array[i] << " ";
    std::cout << std::endl;
}

Compiler et exécuter:

g++ -o main.out -std=c++11 main.cpp
./main.out

Sortie:

0 8 16 24 
00 8 10 18 
0 8 16 24

Testé sur Ubuntu 16.04, GCC 6.4.0.