У меня есть:
uint8 buf[] = {0, 1, 10, 11};
Я хочу преобразовать массив байтов в строку, чтобы я мог распечатать строку с помощью printf:
printf("%s\n", str);
и получаем (двоеточия не нужны):
"00:01:0A:0B"
Любая помощь будет принята с благодарностью.
buf[i]
должен быть переданunsigned char
, иначе он переполнится, еслиbuf[i] > 127
, а именно:buf_ptr += sprintf(buf_ptr, "%02X", (unsigned char)buf[i]);
Ответы:
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
для более общего способа:
int i; for (i = 0; i < x; i++) { if (i > 0) printf(":"); printf("%02X", buf[i]); } printf("\n");
для объединения со строкой есть несколько способов сделать это ... я бы, вероятно, сохранил указатель на конец строки и использовал sprintf. вы также должны отслеживать размер массива, чтобы убедиться, что он не превышает выделенное пространство:
int i; char* buf2 = stringbuf; char* endofbuf = stringbuf + sizeof(stringbuf); for (i = 0; i < x; i++) { /* i use 5 here since we are going to add at most 3 chars, need a space for the end '\n' and need a null terminator */ if (buf2 + 5 < endofbuf) { if (i > 0) { buf2 += sprintf(buf2, ":"); } buf2 += sprintf(buf2, "%02X", buf[i]); } } buf2 += sprintf(buf2, "\n");
источник
printf("%02X", (unsigned char)buf[i]);
следует использовать, так как оригинал вызовет переполнение для беззнаковых символовprintf("%02hhX", buf[i])
?Для полноты, вы также можете легко сделать это без вызова какой-либо тяжелой библиотечной функции (без snprintf, без strcat, даже без memcpy). Это может быть полезно, например, если вы программируете какой-либо микроконтроллер или ядро ОС, где libc недоступна.
Ничего особенного, вы не можете найти похожий код, если погуглите. На самом деле это не намного сложнее, чем вызов snprintf, и намного быстрее.
#include <stdio.h> int main(){ unsigned char buf[] = {0, 1, 10, 11}; /* target buffer should be large enough */ char str[12]; unsigned char * pin = buf; const char * hex = "0123456789ABCDEF"; char * pout = str; int i = 0; for(; i < sizeof(buf)-1; ++i){ *pout++ = hex[(*pin>>4)&0xF]; *pout++ = hex[(*pin++)&0xF]; *pout++ = ':'; } *pout++ = hex[(*pin>>4)&0xF]; *pout++ = hex[(*pin)&0xF]; *pout = 0; printf("%s\n", str); }
Вот еще одна немного более короткая версия. Он просто избегает промежуточной индексной переменной i и дублирования последнего кода регистра (но завершающий символ записывается два раза).
#include <stdio.h> int main(){ unsigned char buf[] = {0, 1, 10, 11}; /* target buffer should be large enough */ char str[12]; unsigned char * pin = buf; const char * hex = "0123456789ABCDEF"; char * pout = str; for(; pin < buf+sizeof(buf); pout+=3, pin++){ pout[0] = hex[(*pin>>4) & 0xF]; pout[1] = hex[ *pin & 0xF]; pout[2] = ':'; } pout[-1] = 0; printf("%s\n", str); }
Ниже приведена еще одна версия ответа на комментарий, в котором говорится, что я использовал «трюк», чтобы узнать размер входного буфера. На самом деле это не уловка, а необходимые входные знания (вам нужно знать размер данных, которые вы конвертируете). Я сделал это яснее, выделив код преобразования в отдельную функцию. Я также добавил код проверки границ для целевого буфера, который на самом деле не нужен, если мы знаем, что делаем.
#include <stdio.h> void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) { unsigned char * pin = in; const char * hex = "0123456789ABCDEF"; char * pout = out; for(; pin < in+insz; pout +=3, pin++){ pout[0] = hex[(*pin>>4) & 0xF]; pout[1] = hex[ *pin & 0xF]; pout[2] = ':'; if (pout + 3 - out > outsz){ /* Better to truncate output string than overflow buffer */ /* it would be still better to either return a status */ /* or ensure the target buffer is large enough and it never happen */ break; } } pout[-1] = 0; } int main(){ enum {insz = 4, outsz = 3*insz}; unsigned char buf[] = {0, 1, 10, 11}; char str[outsz]; tohex(buf, insz, str, outsz); printf("%s\n", str); }
источник
in
выводаout
? Я также мог бы использовать строку и возвращать копию вместо предоставления выходного буфера, в современных оптимизаторах C ++ достаточно хороши, чтобы это не волновало.Вот способ, который работает намного быстрее:
#include <stdlib.h> #include <stdio.h> unsigned char * bin_to_strhex(const unsigned char *bin, unsigned int binsz, unsigned char **result) { unsigned char hex_str[]= "0123456789abcdef"; unsigned int i; if (!(*result = (unsigned char *)malloc(binsz * 2 + 1))) return (NULL); (*result)[binsz * 2] = 0; if (!binsz) return (NULL); for (i = 0; i < binsz; i++) { (*result)[i * 2 + 0] = hex_str[(bin[i] >> 4) & 0x0F]; (*result)[i * 2 + 1] = hex_str[(bin[i] ) & 0x0F]; } return (*result); } int main() { //the calling unsigned char buf[] = {0,1,10,11}; unsigned char * result; printf("result : %s\n", bin_to_strhex((unsigned char *)buf, sizeof(buf), &result)); free(result); return 0 }
источник
ca9e3c972f1c5db40c0b4a66ab5bc1a20ca4457bdbe5e0f8925896d5ed37d726
и у вас все получитсяÌaÌe3cÌ72f1c5dÌ40c0b4a66Ìb5bÌ1Ì20cÌ4457bÌbÌ5Ì0Ì8Ì258Ì6Ì5Ìd37Ì726
. Чтобы исправить это, бит внутриhex_str
первой строки цикла for необходимо изменить на(input[i] >> 4) & 0x0F
как в ответе @kriss. Тогда нормально работает.Подобные ответы уже существуют выше, я добавил этот, чтобы объяснить, как именно работает следующая строка кода:
ptr += sprintf(ptr, "%02X", buf[i])
Это довольно сложно и непросто понять, я помещаю объяснение в комментариях ниже:
uint8 buf[] = {0, 1, 10, 11}; /* Allocate twice the number of bytes in the "buf" array because each byte would * be converted to two hex characters, also add an extra space for the terminating * null byte. * [size] is the size of the buf array */ char output[(size * 2) + 1]; /* pointer to the first item (0 index) of the output array */ char *ptr = &output[0]; int i; for (i = 0; i < size; i++) { /* "sprintf" converts each byte in the "buf" array into a 2 hex string * characters appended with a null byte, for example 10 => "0A\0". * * This string would then be added to the output array starting from the * position pointed at by "ptr". For example if "ptr" is pointing at the 0 * index then "0A\0" would be written as output[0] = '0', output[1] = 'A' and * output[2] = '\0'. * * "sprintf" returns the number of chars in its output excluding the null * byte, in our case this would be 2. So we move the "ptr" location two * steps ahead so that the next hex string would be written at the new * location, overriding the null byte from the previous hex string. * * We don't need to add a terminating null byte because it's been already * added for us from the last hex string. */ ptr += sprintf(ptr, "%02X", buf[i]); } printf("%s\n", output);
источник
Я просто хотел добавить следующее, даже если это немного не по теме (не стандартный C), но я часто ищу его и натыкаюсь на этот вопрос среди первых результатов поиска. Функция печати ядра Linux
printk
также имеет спецификаторы формата для вывода содержимого массива / памяти «напрямую» через спецификатор единственного формата:https://www.kernel.org/doc/Documentation/printk-formats.txt
Raw buffer as a hex string: %*ph 00 01 02 ... 3f %*phC 00:01:02: ... :3f %*phD 00-01-02- ... -3f %*phN 000102 ... 3f For printing a small buffers (up to 64 bytes long) as a hex string with certain separator. For the larger buffers consider to use print_hex_dump().
... однако эти спецификаторы формата, похоже, не существуют для стандартного пользовательского пространства
(s)printf
.источник
Решение
Функция
btox
преобразует произвольные данные*bb
к несогласованной строке*xp
изn
шестнадцатеричных цифр:void btox(char *xp, const char *bb, int n) { const char xx[]= "0123456789ABCDEF"; while (--n >= 0) xp[n] = xx[(bb[n>>1] >> ((1 - (n&1)) << 2)) & 0xF]; }
пример
#include <stdio.h> typedef unsigned char uint8; void main(void) { uint8 buf[] = {0, 1, 10, 11}; int n = sizeof buf << 1; char hexstr[n + 1]; btox(hexstr, buf, n); hexstr[n] = 0; /* Terminate! */ printf("%s\n", hexstr); }
Результат:
00010A0B
.В прямом эфире: Tio.run .
источник
Это один из способов выполнения преобразования:
#include<stdio.h> #include<stdlib.h> #define l_word 15 #define u_word 240 char *hex_str[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; main(int argc,char *argv[]) { char *str = malloc(50); char *tmp; char *tmp2; int i=0; while( i < (argc-1)) { tmp = hex_str[*(argv[i]) & l_word]; tmp2 = hex_str[*(argv[i]) & u_word]; if(i == 0) { memcpy(str,tmp2,1); strcat(str,tmp);} else { strcat(str,tmp2); strcat(str,tmp);} i++; } printf("\n********* %s *************** \n", str); }
источник
Немного измененная версия Яннита. Просто мне нравится, когда это возвращаемое значение
typedef struct { size_t len; uint8_t *bytes; } vdata; char* vdata_get_hex(const vdata data) { char hex_str[]= "0123456789abcdef"; char* out; out = (char *)malloc(data.len * 2 + 1); (out)[data.len * 2] = 0; if (!data.len) return NULL; for (size_t i = 0; i < data.len; i++) { (out)[i * 2 + 0] = hex_str[(data.bytes[i] >> 4) & 0x0F]; (out)[i * 2 + 1] = hex_str[(data.bytes[i] ) & 0x0F]; } return out; }
источник
Эта функция подходит, когда пользователь / вызывающий хочет поместить шестнадцатеричную строку в массив / буфер символов. С шестнадцатеричной строкой в символьном буфере пользователь / вызывающий может использовать свой собственный макрос / функцию, чтобы отображать или регистрировать ее в любом месте (например, в файле). Эта функция также позволяет вызывающему абоненту контролировать количество (шестнадцатеричных) байтов, помещаемых в каждую строку.
/** * @fn * get_hex * * @brief * Converts a char into bunary string * * @param[in] * buf Value to be converted to hex string * @param[in] * buf_len Length of the buffer * @param[in] * hex_ Pointer to space to put Hex string into * @param[in] * hex_len Length of the hex string space * @param[in] * num_col Number of columns in display hex string * @param[out] * hex_ Contains the hex string * @return void */ static inline void get_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col) { int i; #define ONE_BYTE_HEX_STRING_SIZE 3 unsigned int byte_no = 0; if (buf_len <= 0) { if (hex_len > 0) { hex_[0] = '\0'; } return; } if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1) { return; } do { for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i ) { snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff); hex_ += ONE_BYTE_HEX_STRING_SIZE; hex_len -=ONE_BYTE_HEX_STRING_SIZE; buf_len--; } if (buf_len > 1) { snprintf(hex_, hex_len, "\n"); hex_ += 1; } } while ((buf_len) > 0 && (hex_len > 0)); }
Пример: код
#define DATA_HEX_STR_LEN 5000 char data_hex_str[DATA_HEX_STR_LEN]; get_hex(pkt, pkt_len, data_hex_str, DATA_HEX_STR_LEN, 16); // ^^^^^^^^^^^^ ^^ // Input byte array Number of (hex) byte // to be converted to hex string columns in hex string printf("pkt:\n%s",data_hex_str)
ВЫХОД
pkt: BB 31 32 00 00 00 00 00 FF FF FF FF FF FF DE E5 A8 E2 8E C1 08 06 00 01 08 00 06 04 00 01 DE E5 A8 E2 8E C1 67 1E 5A 02 00 00 00 00 00 00 67 1E 5A 01
источник
В C нет примитива для этого. Я бы, вероятно, malloc (или, возможно, alloca) достаточно длинный буфер и перебирал бы ввод. Я также видел, как это было сделано с помощью динамической строковой библиотеки с семантикой (но не синтаксисом!), Аналогичной C ++
ostringstream
, которая является более универсальным решением, но может не стоить дополнительной сложности только для одного случая.источник
Если вы хотите сохранить шестнадцатеричные значения в
char *
строке, вы можете использоватьsnprintf
. Вам необходимо выделить место для всех печатных символов, включая ведущие нули и двоеточие.Расширяя ответ Марка:
char str_buf* = malloc(3*X + 1); // X is the number of bytes to be converted int i; for (i = 0; i < x; i++) { if (i > 0) snprintf(str_buf, 1, ":"); snprintf(str_buf, 2, "%02X", num_buf[i]); // need 2 characters for a single hex value } snprintf(str_buf, 2, "\n\0"); // dont forget the NULL byte
Итак, теперь
str_buf
будет содержать шестнадцатеричную строку.источник
Решение ZincX адаптировано для включения разделителей толстой кишки:
char buf[] = {0,1,10,11}; int i, size = sizeof(buf) / sizeof(char); char *buf_str = (char*) malloc(3 * size), *buf_ptr = buf_str; if (buf_str) { for (i = 0; i < size; i++) buf_ptr += sprintf(buf_ptr, i < size - 1 ? "%02X:" : "%02X\0", buf[i]); printf("%s\n", buf_str); free(buf_str); }
источник
Я добавлю сюда версию на C ++ для всех, кому интересно.
#include <iostream> #include <iomanip> inline void print_bytes(char const * buffer, std::size_t count, std::size_t bytes_per_line, std::ostream & out) { std::ios::fmtflags flags(out.flags()); // Save flags before manipulation. out << std::hex << std::setfill('0'); out.setf(std::ios::uppercase); for (std::size_t i = 0; i != count; ++i) { auto current_byte_number = static_cast<unsigned int>(static_cast<unsigned char>(buffer[i])); out << std::setw(2) << current_byte_number; bool is_end_of_line = (bytes_per_line != 0) && ((i + 1 == count) || ((i + 1) % bytes_per_line == 0)); out << (is_end_of_line ? '\n' : ' '); } out.flush(); out.flags(flags); // Restore original flags. }
Он напечатает шестнадцатеричный дамп
buffer
длиныcount
доstd::ostream
out
(вы можете сделать это по умолчаниюstd::cout
). Каждая строка будет содержатьbytes_per_line
байты, каждый байт представлен в виде двухзначного шестнадцатеричного кода в верхнем регистре. Между байтами будет пробел. И в конце строки или в конце буфера он напечатает новую строку. Еслиbytes_per_line
установлено в 0, то новая_строка печататься не будет. Попробуйте сами.источник
Для простого использования я сделал функцию, которая кодирует входную строку (двоичные данные):
/* Encodes string to hexadecimal string reprsentation Allocates a new memory for supplied lpszOut that needs to be deleted after use Fills the supplied lpszOut with hexadecimal representation of the input */ void StringToHex(unsigned char *szInput, size_t size_szInput, char **lpszOut) { unsigned char *pin = szInput; const char *hex = "0123456789ABCDEF"; size_t outSize = size_szInput * 2 + 2; *lpszOut = new char[outSize]; char *pout = *lpszOut; for (; pin < szInput + size_szInput; pout += 2, pin++) { pout[0] = hex[(*pin >> 4) & 0xF]; pout[1] = hex[*pin & 0xF]; } pout[0] = 0; }
Применение:
unsigned char input[] = "This is a very long string that I want to encode"; char *szHexEncoded = NULL; StringToHex(input, strlen((const char *)input), &szHexEncoded); printf(szHexEncoded); // The allocated memory needs to be deleted after usage delete[] szHexEncoded;
источник
На основе Яннута ответа но упрощенно.
Здесь
dest[]
подразумевается , что длина в два раза большеlen
, и ее распределение управляется вызывающей стороной.void create_hex_string_implied(const unsigned char *src, size_t len, unsigned char *dest) { static const unsigned char table[] = "0123456789abcdef"; for (; len > 0; --len) { unsigned char c = *src++; *dest++ = table[c >> 4]; *dest++ = table[c & 0x0f]; } }
источник
Я знаю, что на этот вопрос уже есть ответ, но я думаю, что мое решение может кому-то помочь.
Итак, в моем случае у меня был массив байтов, представляющий ключ, и мне нужно было преобразовать этот массив байтов в массив шестнадцатеричных значений char, чтобы распечатать его в одной строке. Я извлек свой код в такую функцию:
char const * keyToStr(uint8_t const *key) { uint8_t offset = 0; static char keyStr[2 * KEY_SIZE + 1]; for (size_t i = 0; i < KEY_SIZE; i++) { offset += sprintf(keyStr + offset, "%02X", key[i]); } sprintf(keyStr + offset, "%c", '\0'); return keyStr; }
Теперь я могу использовать свою функцию так:
Serial.print("Public key: "); Serial.println(keyToStr(m_publicKey));
Serial
Объект является частью библиотеки Arduino иm_publicKey
является членом моего класса со следующим объявлениемuint8_t m_publicKey[32]
.источник
Вы можете решить с помощью snprintf и malloc.
char c_buff[50]; u8_number_val[] = { 0xbb, 0xcc, 0xdd, 0x0f, 0xef, 0x0f, 0x0e, 0x0d, 0x0c }; char *s_temp = malloc(u8_size * 2 + 1); for (uint8_t i = 0; i < u8_size; i++) { snprintf(s_temp + i * 2, 3, "%02x", u8_number_val[i]); } snprintf(c_buff, strlen(s_temp)+1, "%s", s_temp ); printf("%s\n",c_buff); free(s);
ВЫХОД: bbccdd0fef0f0e0d0c
источник
Какие сложные решения!
Маллок и спринты, и забросы, о боже. (Цитата из ОЗ)
и нигде ни одного ремня. Гоша,
как насчет этого?
main() { // the value int value = 16; // create a string array with a '\0' ending ie. 0,0,0 char hex[]= {0,0,'\0'}; char *hex_p=hex; //a working variable int TEMP_int=0; // get me how many 16s are in this code TEMP_int=value/16; // load the first character up with // 48+0 gives you ascii 0, 55+10 gives you ascii A if (TEMP_int<10) {*hex_p=48+TEMP_int;} else {*hex_p=55+TEMP_int;} // move that pointer to the next (less significant byte)<BR> hex_p++; // get me the remainder after I have divied by 16 TEMP_int=value%16; // 48+0 gives you ascii 0, 55+10 gives you ascii A if (TEMP_int<10) {*hex_p=48+TEMP_int;} else {*hex_p=55+TEMP_int;} // print the result printf("%i , 0x%s",value,hex); }
источник