Eu tenho:
uint8 buf[] = {0, 1, 10, 11};
Quero converter a matriz de bytes em uma string de forma que possa imprimir a string usando printf:
printf("%s\n", str);
e obter (os dois pontos não são necessários):
"00:01:0A:0B"
Qualquer ajuda seria muito apreciada.
buf[i]
deve ser lançado paraunsigned char
, ou irá transbordar sebuf[i] > 127
, isto é:buf_ptr += sprintf(buf_ptr, "%02X", (unsigned char)buf[i]);
Respostas:
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
para uma forma mais genérica:
int i; for (i = 0; i < x; i++) { if (i > 0) printf(":"); printf("%02X", buf[i]); } printf("\n");
para concatenar em uma string, existem algumas maneiras de fazer isso ... eu provavelmente manteria um ponteiro para o final da string e usaria sprintf. você também deve acompanhar o tamanho da matriz para garantir que ela não fique maior do que o espaço alocado:
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");
fonte
printf("%02X", (unsigned char)buf[i]);
deve ser usado porque o original causará estouro de caracteres não assinadosprintf("%02hhX", buf[i])
?Para completude, você também pode fazer isso facilmente sem chamar qualquer função de biblioteca pesada (sem snprintf, sem strcat, nem mesmo memcpy). Pode ser útil, digamos, se você estiver programando algum microcontrolador ou kernel do sistema operacional onde libc não está disponível.
Nada realmente sofisticado que você possa encontrar código semelhante por aí se você procurar por ele no Google. Na verdade, não é muito mais complicado do que chamar snprintf e muito mais rápido.
#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); }
Aqui está outra versão um pouco mais curta. Ele simplesmente evita a variável de índice intermediária i e a duplicação do último código de caso (mas o caractere de terminação é escrito duas vezes).
#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); }
Abaixo está outra versão para responder a um comentário dizendo que usei um "truque" para saber o tamanho do buffer de entrada. Na verdade, não é um truque, mas um conhecimento de entrada necessário (você precisa saber o tamanho dos dados que está convertendo). Deixei isso mais claro extraindo o código de conversão para uma função separada. Também adicionei o código de verificação de limite para o buffer de destino, o que não é realmente necessário se sabemos o que estamos fazendo.
#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); }
fonte
in
e buffer de saídaout
? Eu também poderia optar por usar uma string e retornar uma cópia em vez de fornecer buffer de saída, em otimizadores C ++ modernos são bons o suficiente para não se importar muito.Aqui está um método muito mais rápido:
#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 }
fonte
ca9e3c972f1c5db40c0b4a66ab5bc1a20ca4457bdbe5e0f8925896d5ed37d726
e vocêÌaÌe3cÌ72f1c5dÌ40c0b4a66Ìb5bÌ1Ì20cÌ4457bÌbÌ5Ì0Ì8Ì258Ì6Ì5Ìd37Ì726
sairá. Para corrigir isso, o bit dentrohex_str
da primeira linha do loop for precisa ser alterado para(input[i] >> 4) & 0x0F
como na resposta de @kriss. Então funciona bem.Já existem respostas semelhantes acima, adicionei esta para explicar como a seguinte linha de código funciona exatamente:
ptr += sprintf(ptr, "%02X", buf[i])
É tranquilo complicado e não é fácil de entender, coloco a explicação nos comentários abaixo:
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);
fonte
Eu só queria adicionar o seguinte, mesmo que seja um pouco fora do tópico (não o padrão C), mas eu me pego procurando por isso com frequência e me deparando com essa questão entre os primeiros resultados de pesquisa. A função de impressão do kernel do Linux,,
printk
também tem especificadores de formato para a saída de conteúdo de array / memória "diretamente" por meio de um especificador de formato singular: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().
... entretanto, esses especificadores de formato não parecem existir para o espaço do usuário padrão
(s)printf
.fonte
Solução
A função
btox
converte dados arbitrários*bb
em uma string não terminada*xp
den
dígitos hexadecimais: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]; }
Exemplo
#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); }
Resultado:
00010A0B
.Ao vivo: Tio.run .
fonte
Esta é uma forma de realizar a conversão:
#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); }
fonte
Versão Yannith ligeiramente modificada. É que gosto de tê-lo como um valor de retorno
fonte
Esta função é adequada onde o usuário / chamador deseja que a string hexadecimal seja colocada em um buffer / array de caracteres. Com a string hexadecimal em um buffer de caracteres, o usuário / chamador pode usar sua própria macro / função para exibi-la ou registrá-la em qualquer lugar que desejar (por exemplo, em um arquivo). Esta função também permite que o chamador controle o número de bytes (hex) para colocar em cada linha.
/** * @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)); }
Exemplo: Código
#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)
RESULTADO
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
fonte
Não há nenhum primitivo para isso em C. Eu provavelmente malloc (ou talvez alloca) um buffer longo o suficiente e faço um loop sobre a entrada. Também vi isso ser feito com uma biblioteca de string dinâmica com semântica (mas não sintaxe!) Semelhante à do C ++
ostringstream
, que é uma solução plausivelmente mais genérica, mas pode não valer a pena a complexidade extra apenas para um único caso.fonte
Se você deseja armazenar os valores hexadecimais em uma
char *
string, você pode usarsnprintf
. Você precisa alocar espaço para todos os caracteres impressos, incluindo os zeros à esquerda e dois pontos.Expandindo a resposta de Mark:
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
Portanto, agora
str_buf
conterá a string hexadecimal.fonte
A solução do ZincX adaptada para incluir delimitadores de dois pontos:
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); }
fonte
Vou adicionar a versão C ++ aqui para quem estiver interessado.
#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. }
Ele imprimirá o hexdump de
buffer
de comprimentocount
parastd::ostream
out
(você pode torná-lo padrãostd::cout
). Cada linha conterábytes_per_line
bytes, cada byte é representado usando hexadecimal de dois dígitos maiúsculos. Haverá um espaço entre os bytes. E no final da linha ou final do buffer, ele imprimirá uma nova linha. Sebytes_per_line
estiver definido como 0, não imprimirá nova linha. Experimente você mesmo.fonte
Para um uso simples, criei uma função que codifica a string de entrada (dados binários):
/* 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; }
Uso:
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;
fonte
Com base na resposta de Yannuth, mas simplificada.
Aqui, o comprimento de
dest[]
está implícito como sendo o dobro delen
e sua alocação é gerenciada pelo chamador.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]; } }
fonte
Sei que essa pergunta já tem uma resposta, mas acho que minha solução pode ajudar alguém.
Portanto, no meu caso, eu tinha uma matriz de bytes representando a chave e precisava converter essa matriz de bytes em uma matriz char de valores hexadecimais para imprimi-la em uma linha. Extraí meu código para uma função como esta:
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; }
Agora, posso usar minha função assim:
Serial.print("Public key: "); Serial.println(keyToStr(m_publicKey));
Serial
object faz parte da biblioteca Arduino em_publicKey
é membro da minha classe com a seguinte declaraçãouint8_t m_publicKey[32]
.fonte
Você pode resolver com snprintf e 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);
OUT: bbccdd0fef0f0e0d0c
fonte
Que soluções complexas!
Malloc e corre e lança oh meu. (Citação OZ)
e nem um único rem em qualquer lugar. Puxa, que tal
algo assim?
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); }
fonte