Как распечатать байты в шестнадцатеричном формате?

Я знаю, что в С# вы можете использовать метод String.Format. Но как это сделать на С++? Есть ли функция, которая позволяет мне преобразовать байт в шестнадцатеричный?? Просто нужно преобразовать 8-байтовые данные в шестнадцатеричный формат, как мне это сделать?


person Danny    schedule 15.05.2012    source источник
comment
спринтф () ? наполнительнаполнительнаполнитель   -  person Martin James    schedule 15.05.2012
comment
@arrowdodger Извините, да, я хочу, чтобы оно было шестнадцатеричным   -  person Danny    schedule 15.05.2012


Ответы (8)


Ну, вы можете конвертировать один байт (беззнаковый символ) за раз в такой массив

char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
    sprintf(&buffer[2*j], "%02X", data[j]);
person bentech    schedule 15.05.2012
comment
Я предположил, что он хотел преобразовать массив чисел в массив шестнадцатеричных чисел, я думаю, ему, вероятно, нужна была шестнадцатеричная строка. - person bentech; 15.05.2012
comment
Я хотел бы отметить, что это на самом деле C-way, а не C++. Я бы предпочел принять ответ @Component 10. - person arrowd; 15.05.2012
comment
Если рассматриваемый char отрицателен, повышение типа функции с переменным числом аргументов вызовет шесть начальных F. - person imallett; 05.06.2013
comment
Вы, вероятно, пропустили &-char перед буфером[2*j] - person Arthur P. Golubev; 07.11.2015
comment
@imallett да, определенно следует использовать %hhx или unsigned char. Для новичков: печать шестнадцатеричных символов в c - person Rick; 21.11.2019
comment
Вопрос был о C++, а не о C. - person leo60228; 09.12.2019

Если вы хотите использовать потоки C++ вместо функций C, вы можете сделать следующее:

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;

Очень простой.

Вывод:

20 30 40 50 60 70 80 90
14 1e 28 32 3c 46 50 5a 
person Component 10    schedule 15.05.2012
comment
Стоит отметить, что вы должны #include <iomanip> и что hex, setfill и setw все находятся в пространстве имен std. Кроме того, hex является постоянным, поэтому вы можете вытащить его из цикла, и вы должны вызвать dec, когда закончите, чтобы поток печатал будущие целочисленные значения в десятичном виде, предполагая, что это то, что вы хотите. - person Drew Noakes; 31.08.2014
comment
Очень хороший ответ --- можно было бы использовать несколько примеров того, что такое hex и setfill. - person jb.; 21.11.2014
comment
Чтобы разъяснить @Andrew, если у вас есть char c и вы хотите напечатать значения › 0x80 в шестнадцатеричном формате, вам нужно преобразовать его как (unsigned int)(unsigned char)c. В противном случае вы напечатаете 32-битное дополнение до 2. - person jtbr; 28.06.2017
comment
@DrewNoakes Я попытался осветить эти моменты по адресу: stackoverflow.com/a/53673624/895245. - person Ciro Santilli 新疆再教育营六四事件ۍ 07.12.2018
comment
@jbr unsigned char не работает. Для новичков, если у вас есть char a = 20; cout << hex << a << endl;, это даст вам мусор. Поскольку char имеет специальную перегрузку для ostream с operator<<. Итак, вам нужно привести, например. int, как cout << hex << (int)a << endl;. Что касается печатных значений › 0x80 в шестнадцатеричном формате, также требуется приведение. Причина в печати шестнадцатеричных символов в c. - person Rick; 21.11.2019
comment
Только что заметил, что это, вероятно, не то, что хотел ОП. То, что OP хочет для этого массива, вероятно, 00 00 00 20 00 00 00 30. - person Ciro Santilli 新疆再教育营六四事件ۍ 16.08.2020

Печать произвольных структур в современном C++

Все ответы до сих пор говорят вам только о том, как напечатать массив целых чисел, но мы также можем напечатать любую произвольную структуру, зная ее размер. Пример ниже создает такую ​​структуру и перебирает указатель по ее байтам, печатая их на выходе:

#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;
}

И вот результат:

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

Обратите внимание, что этот пример также иллюстрирует работу выравнивания памяти. Мы видим, что version занимает 2 байта (05 00), затем следует msgSize с еще 2 байтами (24 00) и затем 4 байта заполнения, после чего идут someId (34 12 00 00 00 00 00 00) и anotherId (78 56 00 00 00 00 00 00). Затем isFoo, который занимает 1 байт (01), и isBar, еще один байт (01), за которым следуют 6 байтов заполнения, и, наконец, заканчивается стандартным представлением IEEE 754 двойного поля floatingPointValue.

Также обратите внимание, что все значения представлены как little endian (наименее значащие байты идут первыми), так как это было компилируется и работает на платформе Intel.

person Lucio Paiva    schedule 24.11.2017

Это модифицированная версия метода 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;
    }
}
person Mohamed Saad    schedule 05.09.2013

Я не знаю лучшего способа, чем:

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]);
}

Вы можете ускорить его, используя метод 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];

}
person Rick Murtagh    schedule 02.08.2013
comment
Использование sprintf() обычно считается опасным по уважительной причине. Здесь с использованием все в порядке, поскольку вы тщательно выделяете достаточно места, но в целом я бы избегал этого. Мне гораздо больше нравится подход к грызуну. - person cmaster - reinstate monica; 03.08.2013
comment
должно быть const char* szNibbleToHex - person lbenini; 05.05.2016
comment
Или должно быть const char szNibbleToHex[16] = {0123456789ABCDEF}; - person Codebeat; 17.02.2019

Еще один ответ, если массив байтов определен как char[], в верхнем регистре и разделен пробелами.

void debugArray(const unsigned char* data, size_t len) {
    std::ios_base::fmtflags f( std::cout.flags() );
    for (size_t i = 0; i < len; ++i)
        std::cout << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (((int)data[i]) & 0xFF) << " ";
    std::cout << std::endl;
    std::cout.flags( f );
}

Пример:

unsigned char test[]={0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
debugArray(test, sizeof(test));

Вывод:

01 02 03 04 05 06

person daniol    schedule 19.02.2021

Использовать потоки C++ и впоследствии восстанавливать состояние

Это вариант Как печатать байты в шестнадцатеричном формате?< /а> но:

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;
}

Скомпилируйте и запустите:

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

Вывод:

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

Протестировано на Ubuntu 16.04, GCC 6.4.0.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 07.12.2018
comment
Это не потокобезопасно. Это может иметь или не иметь значения, в зависимости от варианта использования. Однако я думаю, что это, по крайней мере, заслуживает упоминания. - person Lightness Races in Orbit; 07.12.2018
comment
О, и это тоже не безопасно для исключений. Вот почему страница, на которую вы ссылаетесь, имеет лучшие альтернативы;) - person Lightness Races in Orbit; 07.12.2018

Еще одна альтернатива C++17, а почему бы и нет!

std::cout<<std::hex<<std::setfill('0');

struct {
    std::uint16_t first{666};
    std::array<char,4> second{'a','b','c','d'};
} my_struct;

auto ptr = reinterpret_cast<std::byte*>(&my_struct);
auto buffer = std::vector<std::byte>(ptr, ptr + sizeof(my_struct));
std::for_each(std::begin(buffer),std::end(buffer),[](auto byte){
    std::cout<<std::setw(2)<<std::to_integer<int>(byte)<<' ';
});

Исполняемый код здесь.

person ambushed    schedule 22.04.2021