C에서 바이트 배열을 16 진수 문자열로 어떻게 변환합니까?
나는 가지고있다:
uint8 buf[] = {0, 1, 10, 11};
printf를 사용하여 문자열을 인쇄 할 수 있도록 바이트 배열을 문자열로 변환하고 싶습니다.
printf("%s\n", str);
다음을 가져옵니다 (콜론은 필요하지 않음).
"00:01:0A:0B"
어떤 도움이라도 대단히 감사하겠습니다.
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");
완전한 경우에는 무거운 라이브러리 함수를 호출하지 않고도 쉽게 수행 할 수 있습니다 (snprintf, strcat, memcpy 없음). libc를 사용할 수없는 마이크로 컨트롤러 나 OS 커널을 프로그래밍하는 경우 유용 할 수 있습니다.
Google에서 검색하면 비슷한 코드를 찾을 수 있습니다. 실제로 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);
}
다음은 훨씬 빠른 방법입니다.
#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
}
비슷한 답변이 위에 이미 존재하므로 다음 코드 줄이 정확히 어떻게 작동하는지 설명하기 위해이 답변을 추가했습니다.
ptr += sprintf (ptr, "%02X", buf[i])
조용히 까다 롭고 이해하기 쉽지 않습니다. 아래 주석에 설명을 넣었습니다.
uint8 buf[] = {0, 1, 10, 11};
/* Allocate twice the number of the 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 to 2 chars hex string and a null byte, for example
* 10 => "0A\0".
*
* These three chars would be added to the output array starting from
* the ptr location, for example if ptr is pointing at 0 index then the hex chars
* "0A\0" would be written as output[0] = '0', output[1] = 'A' and output[2] = '\0'.
*
* sprintf returns the number of chars written execluding the null byte, in our case
* this would be 2. Then we move the ptr location two steps ahead so that the next
* hex char would be written just after this one and overriding this one's null byte.
*
* We don't need to add a terminating null byte because it's already added 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
16 진수 :
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);
}
약간 수정 된 Yannith 버전. 나는 그것을 반환 값으로 갖고 싶습니다.
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;
}
이 함수는 사용자 / 호출자가 16 진수 문자열을 문자 배열 / 버퍼에 넣기를 원하는 경우에 적합합니다. 문자 버퍼의 16 진수 문자열을 사용하면 사용자 / 호출자는 자체 매크로 / 기능을 사용하여 원하는 위치 (예 : 파일)에 표시하거나 기록 할 수 있습니다. 이 함수는 호출자가 각 줄에 넣을 (16 진수) 바이트 수를 제어 할 수도 있습니다.
/**
* @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
그럴듯하게 더 일반적인 솔루션이지만 단일 사례에 대한 추가 복잡성의 가치가 없을 수도 있습니다.
16 진수 값을 char *
문자열 에 저장 하려면 snprintf
. 선행 0과 콜론을 포함하여 인쇄 된 모든 문자에 대해 공간을 할당해야합니다.
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
이제 str_buf
16 진수 문자열이 포함됩니다.
콜론 구분 기호를 포함하도록 조정 된 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.
}
그것은의 16 진 덤프 인쇄 할 buffer
길이를 count
위해 std::ostream
out
(당신이 기본적 할 수 있습니다 std::cout
). 모든 행에는 bytes_per_line
바이트 가 포함 되고 각 바이트는 대문자 2 자리 16 진수로 표시됩니다. 바이트 사이에 공백이 있습니다. 그리고 줄 끝이나 버퍼 끝에서 줄 바꿈을 인쇄합니다. bytes_per_line
가 0으로 설정 되면 new_line을 인쇄하지 않습니다. 스스로 시도하십시오.
간단한 사용법을 위해 입력 문자열 (이진 데이터)을 인코딩하는 함수를 만들었습니다.
/* 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;
Yannuth의 답변을 기반으로 하지만 단순화되었습니다.
여기서의 길이는의 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];
}
}
이 질문에 이미 답이 있다는 것을 알고 있지만 내 솔루션이 누군가를 도울 수 있다고 생각합니다.
So, in my case I had a byte array representing the key and I needed to convert this byte array to char array of hexadecimal values in order to print it out in one line. I extracted my code to a function like this:
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;
}
Now, I can use my function like this:
Serial.print("Public key: ");
Serial.println(keyToStr(m_publicKey));
Serial
object is part of Arduino library and m_publicKey
is member of my class with the following declaration uint8_t m_publicKey[32]
.
What complex solutions!
Malloc and sprints and casts oh my. (OZ quote)
and not a single rem anywhere. Gosh
How about something like this?
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);
}
'Development Tip' 카테고리의 다른 글
Intent를 통해 ArrayList 전달 (0) | 2020.10.16 |
---|---|
Git 저장소 및 GitHub의 원격에서 파일을 완전히 제거 (0) | 2020.10.16 |
실행 가능한 jar 라이브러리 처리 옵션의 차이점은 무엇입니까? (0) | 2020.10.16 |
유효성 검사 오류 : 값이 유효하지 않습니다. (0) | 2020.10.16 |
바인딩이 클로저보다 느린 이유는 무엇입니까? (0) | 2020.10.16 |