Я знаю, что в С# вы можете использовать метод String.Format. Но как это сделать на С++? Есть ли функция, которая позволяет мне преобразовать байт в шестнадцатеричный?? Просто нужно преобразовать 8-байтовые данные в шестнадцатеричный формат, как мне это сделать?
Как распечатать байты в шестнадцатеричном формате?
Ответы (8)
Ну, вы можете конвертировать один байт (беззнаковый символ) за раз в такой массив
char buffer [17];
buffer[16] = 0;
for(j = 0; j < 8; j++)
sprintf(&buffer[2*j], "%02X", data[j]);
%hhx
или unsigned char
. Для новичков: печать шестнадцатеричных символов в c
- person Rick; 21.11.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
#include <iomanip>
и что hex
, setfill
и setw
все находятся в пространстве имен std
. Кроме того, hex
является постоянным, поэтому вы можете вытащить его из цикла, и вы должны вызвать dec
, когда закончите, чтобы поток печатал будущие целочисленные значения в десятичном виде, предполагая, что это то, что вы хотите.
- person Drew Noakes; 31.08.2014
hex
и setfill
.
- person jb.; 21.11.2014
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
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.
Это модифицированная версия метода 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;
}
}
Я не знаю лучшего способа, чем:
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];
}
sprintf()
обычно считается опасным по уважительной причине. Здесь с использованием все в порядке, поскольку вы тщательно выделяете достаточно места, но в целом я бы избегал этого. Мне гораздо больше нравится подход к грызуну.
- person cmaster - reinstate monica; 03.08.2013
const char* szNibbleToHex
- person lbenini; 05.05.2016
Еще один ответ, если массив байтов определен как 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
Использовать потоки C++ и впоследствии восстанавливать состояние
Это вариант Как печатать байты в шестнадцатеричном формате?< /а> но:
- работоспособный
- учитывая, что это изменяет состояние cout и пытается восстановить его в конце, как указано в: Восстановить состояние std::cout после манипулирования им
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.
Еще одна альтернатива 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)<<' ';
});
Исполняемый код здесь.