Related
I'm playing around doing a few challenges of reverse engineering with ghidra.
I have analyzed a bin file, which should contain some information about a password.
When you run the file, you can give it some input, and it will check if it's the correct password.
Here is the pseudo-c code that is responsible for doing this (The comments are me):
__isoc99_scanf(&DAT_00400a82,local_28); // input scanned from user
__s2 = (char *)FUN_0040078d(0x14); // password retrieved from function
iVar1 = strcmp(local_28,__s2); // comparing strings
if (iVar1 == 0) { // if they are equal, do this
FUN_00400978(&local_48);
}
Ok, so i tried looking up the function FUN_0040078d:
void * FUN_0040078d(int param_1)
{
int iVar1;
time_t tVar2;
void *pvVar3;
int local_c;
tVar2 = time((time_t *)0x0);
DAT_00601074 = DAT_00601074 + 1;
srand(DAT_00601074 + (int)tVar2 * param_1);
pvVar3 = malloc((long)(param_1 + 1));
if (pvVar3 != (void *)0x0) {
local_c = 0;
while (local_c < param_1) {
iVar1 = rand();
*(char *)((long)local_c + (long)pvVar3) = (char)(iVar1 % 0x5e) + '!';
local_c = local_c + 1;
}
*(undefined *)((long)pvVar3 + (long)param_1) = 0;
return pvVar3;
}
/* WARNING: Subroutine does not return */
exit(1);
}
So theres a lot of information here. But overall, what I think happens is that an array of chars is constructed, by doing the operation:
(char)(iVar1 % 0x5e) + '!';
Which I have no idea what means (what does modulo on chars do? and does + '!' ) just mean concatenate a "!".
Overall I'm haivng some issues reading this, and I'm wondering if it's possible to predict what this function would output for specific inputs. In this case the function is given 14 as input.
Maybe the use of the rand() means that it cannot be deconstructed?
Can anyone give a guess/tell me whatthis function would likely output for input 14?
you got to remember that every char is a character representation of an 8bit value. Thus every operator is valid within the realm of chars.
I made this example for you to understand it better.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char character = 'A'; // 65 in dec
char bang = '!'; // 33 in dec
printf("'A' in dec: %d\n", (int)character);
printf("'!' in dec: %d\n", (int)bang);
// now the modulo operator works the same in chars
character = 'a';
char new_value = (char)character%64;
printf("a %% 64 : char_value: %c, int_value: %d\n", new_value, (int)new_value);
// you got to remember that chars are just a coded 8bit value
char at_symbol = '#'; // 64 in dec
// now the modulo operator works the same in chars
character = 'a';
new_value = (char)character%at_symbol;
printf("a %% # : char_value: %c, int_value: %d\n", new_value, (int)new_value);
// it works the same with every other operator
int value1 = 300; //this is your random value
char hex_value = 0x5E; //94 in dec or ^ in char
new_value = (char)(value1%hex_value); //300 % 94 = 18;
new_value += bang; //18 + 33 = 51 in dec or the number 3 symbol in char;
printf("dec_val: %d, char encoding: %c\n", (int)new_value, new_value);
}
as per your previous comment, here's a simplified version of your function
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
long GLOBAL_COUNTER = 0;
typedef char undefined;
void * array_constructor(int size);
int main(int argc, char **argv)
{
char* random_string = (char*)array_constructor(0x14);
printf("%s", random_string);
free(random_string);
}
void * array_constructor(int size)
{
int random_value;
//time_t cur_time;
void *array;
int counter;
//cur_time = time(NULL);
GLOBAL_COUNTER = GLOBAL_COUNTER + 1;
srand(0);//srand(GLOBAL_COUNTER + (int)cur_time * param_1);
array = malloc((long)(size + 1));//returns a void array of param_1 + 1 elements
if (array == NULL)
exit(1);
counter = 0;
while (counter < size) {
random_value = rand();
int char_value = (char)(random_value % 0x5e) + '!';//Range of possible values 33-127
// This is due to the fact that random value can have any value given the seed
// but its truncated to a modulo 0x5e so its new range is 0 - 0x5e(94 in dec)
// and you add the bang symbol at the end so 0 + 33 = 33 and 94 + 33 = 127
*(char *)((long)counter + (long)array) = char_value;
// this statement is the same as
// array[counter] = char_value
counter++;
}
*(undefined *)((long)array + (long)size) = 0; //it puts the \0 at the end of the string
return array;
}
now the only problem that you had was with the undefined typedef. this code is a simplification of yours. but it works.
I am trying to center align strings in a total of 16 spaces to eventually print them on a 16x2 LCD Display. The values are grabbed from a database, and put in a global variable that is constantly being updated.
The values in the database are already in string format.
What I'd like to do is after getting the value from the DB, update the global variable to contain a string centered in 16 spaces.
I understand using global variables may not be best practice but ignoring that is there a way to do this?
char * systemInfoValues[5] = {" "," "," "," "," "}
for(int i=0; i< 5; i++){
systemInfoValues[i] = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
sprintf(tmp,"%*s", (17-len)/2 + len, systemInfoValues[i]);
strcpy(systemInfoValues[i],tmp);
}
0 = a blank space
xxxxx = string from db
If the length of the string is odd
I expect the output to be [00xxxxxxxxxxxxx0]
if the length of the string is even
I expect the output to be [00xxxxxxxxxxxx00]
It is simple 6 line function. symetry is giving you the option
char *centerinstring(char *buff, size_t len, const char *str, int symetry)
{
size_t strl = strlen(str);
size_t pos = (len - strl) / 2 + (strl & 1) * !!symetry;
memset(buff,' ', len);
buff[len] = 0;
memmove(buff + pos, str, strl);
return buff;
}
int main()
{
char buff[11];
printf("|%s|\n", centerinstring(buff, 10, "1234567", 1));
printf("|%s|\n", centerinstring(buff, 10, "1234567", 0));
return 0;
}
or with the option to allocate memory for the buff (if you pass NULL
char *centerinstring(char *buff, size_t len, const char *str, int symetry)
{
size_t strl = strlen(str);
size_t pos = strl / 2 + (strl & 1) * !!symetry;
buff = buff ? malloc(len + 1) : buff;
if(buff)
{
memset(buff,' ', len);
buff[len] = 0;
memmove(buff + pos, str, strl);
}
return buff;
}
sprintf()-comfort:
#include <assert.h>
#include <string.h>
#include <stdio.h>
void center(char *dst, char *src, size_t width)
{
assert(dst && src && width);
size_t src_len = strlen(src);
if (src_len >= width) {
*dst = '\0';
return;
}
int right = (int)(width - src_len) / 2;
int left = right + (int)src_len;
right -= (src_len & 1);
sprintf(dst, "%*s%*s", left, src, right, "");
}
int main(void)
{
char destination[17];
center(destination, "12345678901234", sizeof(destination));
printf("\"%s\"\n", destination);
}
You can do it in another way (without using the sprintf function).
I don't know about any interface of the sprintf function that would allow you to do it, but you can solve the problem using simple strcpy of variables.
This is a main program that would solve your problem, it is documented in itself, so you should be able to understand how to apply this to your code:
#include <stdio.h>
#include <string.h>
/* This simple program would transfer the original string that is in the
* out_value to be centralized in this variable. */
int main(void) {
char out_value[17] = "1234567891";
char temp[20] = {0};
int first_index = 0;
int string_length = 0;
/* Copy the string to the temp variable, to modify the chars in
* out_value. */
strcpy(temp, out_value);
/* Find out the index for the first char to be placed in the centralized
* string. */
string_length = strlen(temp);
first_index = (16 - string_length) / 2;
/* Set all the values of the out_value to be the wanted value of space (here
* it is 0 for visualizing, it can be space to not be present). */
memset(out_value, '0', 16);
/* Copy the original string back, moving the start of it, so it would be
* centralized. */
strncpy(&(out_value[first_index]), temp, string_length);
/* Print the string. */
printf("%s", out_value);
}
When modifying your code to work with this, the code would look something like this:
char * systemInfoValues[5] = {NULL}
for(int i=0; i< 5; i++){
systemInfoValues[i] = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
int first_index = 0;
strcpy(tmp, systemInfoValues[i]);
first_index = (16 - len) / 2;
memset(systemInfoValues[i], ' ', 16);
strncpy(&(systemInfoValues[i][first_index]), tmp, len);
}
Note that I changed the initializing of the value of systemInfoValues. When you initialized it, you put empty strings there. Note that this is a bad habit. Putting empty strings there (or strings with a single space) would allocate the memory for this string (which you will never use).
You didn't include the definition to the function of PQgetvalue, but assuming that it would return a char pointer, this should work.
But, this code would change the global value as well. If you don't want to change it, you shoudn't put the result there, but copy the result to the string before doing any changes to it.
After modifying the code, it should look like this:
char systemInfoValues[5][17] = {{0}}
for(int i=0; i< 5; i++){
char *global_reference = PQgetvalue(res,i,0); //get the value from db;
int len = strlen(systemInfoValues[i]);
char tmp[20];
int first_index = 0;
strcpy(tmp, global_reference);
first_index = (16 - len) / 2;
memset(systemInfoValues[i], ' ', 16);
strncpy(&(systemInfoValues[i][first_index]), tmp, len);
}
edit: apperently there is an interface for the sprintf function to work (as you originally wanted). To see it, refer to the answer of Swordfish
I'm having difficulty in generating a string of the form "1,2,3,4,5" to pass to a command line program.
Here's what I have tried:
int N=100;
char list[200];
for (i=0; i<2*N; i+=2) {
char tmp;
sprintf(tmp,'%d', i);
strcpy(list[i], tmp);
strcpy(list[i+1], ',');
}
Edit:
I don't feel this question is a duplicate as it is more to do with appending strings into a list and managing that memory and than literally just putting a comma between to integers.
The following code will do what you need.
#include <stdlib.h>
#include <stdio.h>
char* CommaSeparatedListOfIntegers(const int N)
{
if (N < 1)
return NULL;
char* result = malloc(1 + N*snprintf(NULL, 0, "%d,", N));
char* p = result;
for (int i = 1; i <= N; i++)
p += sprintf(p, "%d,", i);
*(p-1) = '\0';
return result;
}
Note that the function returns a heap allocated block of memory that the caller is responsible for clearing up.
Some points of note:
We put a crude upper bound on the length of each number when converted to text. This does mean that we will over allocate the block of memory, but not by a massive amount. If that is a problem for you then you can code a more accurate length. That would involve looping from 1 to N and calling snprintf for each value to determine the required length.
Note that we initially write out a comma after the final value, but then replace that with the null-terminator.
Let's forget about writing strings for the moment and write a function that just prints that list to the screen:
int range_print(int begin, int end, const char *sep)
{
int len = 0;
int i;
for (i = begin; i < end; i++) {
if (i > begin) {
len += printf("%s", sep);
}
len += printf("%d", i);
}
return len;
}
You can call it like this:
range_print(1, 6, ", ");
printf("\n");
The function does not write a new-line character, so we have to do that. It prints all numbers and a custom separator before each number after the first. The separator can be any string, so this function also works if you want to separate your numbers with slashes or tabs.
The function has printf semantics, because it returns the number of characters written. (That value is often ignored, but it can come in handy, as we'll see soon.) We also make the upper bound exclusive, so that in order to print (1, 2, 3, 4, 5) you have tp pass 1 and 6 as bounds.
We'll now adapt this function so that it writes to a string. There are several ways to do that. Let's look at a way that works similar to snprintf: It should tabe a pre-allocated char buffer, a maximum length and it should return the number of characters written or, if the output doesn't fit, the number of characters that would have been written had the buffer been big enough.
int range(char *buf, int n, int begin, int end, const char *sep)
{
int len = 0;
int m, i;
for (i = begin; i < end; i++) {
m = snprintf(buf, n, "%s%d",
(i > begin) ? sep : "", i);
len += m;
buf += m;
n -= m;
if (n < 0) n = 0;
}
return len;
}
This function is tricky because it has to keep track of the number of characters written and of the free buffer still available. It keeps printing after the buffer is full, which is a bit wasteful in terms of performace, but it is legal to call snprintf with a buffer size of zero, and that way we keep the semantics tidy.
You can call this function like this:
char buf[80];
range(buf, sizeof(buf), 1, 6, ", ");
printf("%s\n", buf);
That means that we need to define a buffer that is large enough. If the range of numbers is large, the string will be truncated. We might therefore want a function that allocates a string for us that is long enough:
char *range_new(int begin, int end, const char *sep, int *plen)
{
int len = (end - begin - 1) * strlen(sep) + 1;
char *str;
char *p;
int i;
for (i = begin; i < end; i++) {
len += snprintf(NULL, 0, "%d", i);
}
str = malloc(len);
if (str == NULL) return NULL;
p = str;
for (i = begin; i < end; i++) {
if (i > begin) p += sprintf(p, "%s", sep);
p += sprintf(p, "%d", i);
}
if (plen) *plen = len - 1;
return str;
}
This function needs two passes: in the first pass, we determine how much memory we need to store the list. Next, we allocate and fill the string. The function returns the allocated string, which the user has to free after use. Because the return value is already used, we lose the information on the string length. An additional argument, a pointer to int, may be given. If it is not NULL, the length will be stored.
This function can be called like this.
char *r;
int len;
r = range_new(1, 6, ", ", &len);
printf("%s (%d)\n", r, len);
free(r);
Note that the same can be achieved by calling our old range function twice:
char *r;
int len;
len = range(NULL, 0, 1, 6, ", ");
r = malloc(len + 1);
range(p, len + 1, 1, 6, ", ");
printf("%s (%d)\n", r, len);
free(r);
So, pick one. For short ranges, I recommend the simple range function with a fixed-size buffer.
I am trying to create a program that is able to rotate at point k, defined as the "rotation requested."
Example: rotate("derp", 3) => pder
My code for this function is called rotate, as listed below. It takes in both a char pointer array, startString, as defined in my main, and the number of rotations (A long int because I use atol to get the integer from the command line).
int rotate(char *startString, long int rotations) {
char *doubleString = malloc((sizeof startString * 2) + sizeof(char));
strcat(doubleString, startString);
strcat(doubleString, startString);
long int stringSize = (sizeof startString - 1);
long int breakIndex = (rotations % stringSize);
char* rotatedString = malloc((sizeof startString + sizeof(char)));
int i;
for (i = 0; i < stringSize + 1; i++) {
char pushedCharacter = doubleString[(int)breakIndex + i];
strcat(rotatedString, &pushedCharacter);
}
printf("%s\n", rotatedString);
printf("%s\n", doubleString);
return 0;
}
But, when I output, if I use something like doghouse I get a weird ?4??? in front of the output for the rotatedString. It also completely doesn't work for derp, instead printing out pderp with the same ?4??? in front. Where is this runtime error being caused?
EDIT
The answer given was correct, but the goal was to be able to accept rotations greater than the length of the given string. That code is below:
void rotate(char * startString, long int rotations) {
long int stringSize = strlen(startString);
long int breakIndex = (rotations % stringSize);
char *rotatedString = malloc(stringSize + 1); //counting extra char for null terminator
strncpy(rotatedString, startString + breakIndex, stringSize - breakIndex);
strncpy(rotatedString + stringSize - breakIndex, startString, breakIndex);
rotatedString[stringSize] = '\0'; // for the ending null character of the char array
printf("Result: %s\n", rotatedString);
free(rotatedString);
}
Your doublestring initialization allocates too little memory because you're using sizeof(startstring), which is the size of a pointer, not strlen(startstring) + 1 which is the length of the string including the terminating NUL character. This means your code is overwriting the end of the buffer with hilarous results. Try the following:
void rotate(char * startString, int rotation) {
int len = strlen(startString);
if (len == 0 || len <= rotation)
return;
char *rotatedString = malloc(len + 1); /* One extra char for the terminating NUL */
strncpy(rotatedString, startString + rotation, len - rotation);
strncpy(rotatedString + len - rotation, startString, rotation);
rotatedString[len] = '\0';
printf("%s\n", rotatedString);
free(rotatedString); /* don't leak memory! */
}
I have:
uint8 buf[] = {0, 1, 10, 11};
I want to convert the byte array to a string such that I can print the string using printf:
printf("%s\n", str);
and get (the colons aren't necessary):
"00:01:0A:0B"
Any help would be greatly appreciated.
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
For a more generic way:
int i;
for (i = 0; i < x; i++)
{
if (i > 0) printf(":");
printf("%02X", buf[i]);
}
printf("\n");
To concatenate to a string, there are a few ways you can do this. I'd probably keep a pointer to the end of the string and use sprintf. You should also keep track of the size of the array to make sure it doesn't get larger than the space allocated:
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");
For completude, you can also easily do it without calling any heavy library function (no snprintf, no strcat, not even memcpy). It can be useful, say if you are programming some microcontroller or OS kernel where libc is not available.
Nothing really fancy you can find similar code around if you google for it. Really it's not much more complicated than calling snprintf and much faster.
#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);
}
Here is another slightly shorter version. It merely avoid intermediate index variable i and duplicating laste case code (but the terminating character is written two times).
#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);
}
Below is yet another version to answer to a comment saying I used a "trick" to know the size of the input buffer. Actually it's not a trick but a necessary input knowledge (you need to know the size of the data that you are converting). I made this clearer by extracting the conversion code to a separate function. I also added boundary check code for target buffer, which is not really necessary if we know what we are doing.
#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);
}
Similar answers already exist above, I added this one to explain how the following line of code works exactly:
ptr += sprintf(ptr, "%02X", buf[i])
It's quiet tricky and not easy to understand, I put the explanation in the comments below:
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);
Here is a method that is way way faster :
#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
}
Solution
Function btox converts arbitrary data *bb to an unterminated string *xp of n hexadecimal digits:
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];
}
Example
#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);
}
Result: 00010A0B.
Live: Tio.run.
I just wanted to add the following, even if it is slightly off-topic (not standard C), but I find myself looking for it often, and stumbling upon this question among the first search hits. The Linux kernel print function, printk, also has format specifiers for outputting array/memory contents "directly" through a singular format specifier:
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().
... however, these format specifiers do not seem to exist for the standard, user-space (s)printf.
This is one way of performing the conversion:
#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);
}
Slightly modified Yannith version.
It is just I like to have it as a return value
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;
}
This function is suitable where user/caller wants hex string to be put in a charactee array/buffer. With hex string in a character buffer, user/caller can use its own macro/function to display or log it to any place it wants (e.g. to a file). This function also allows caller to control number of (hex) bytes to put in each line.
/**
* #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));
}
Example:
Code
#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)
OUTPUT
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
You can solve with snprintf and 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
There's no primitive for this in C. I'd probably malloc (or perhaps alloca) a long enough buffer and loop over the input. I've also seen it done with a dynamic string library with semantics (but not syntax!) similar to C++'s ostringstream, which is a plausibly more generic solution but it may not be worth the extra complexity just for a single case.
ZincX's solution adapted to include colon delimiters:
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);
}
I'll add the C++ version here for anyone who is interested.
#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.
}
It will print the hexdump of the buffer of length count to std::ostream out (you can make it default to std::cout). Every line will contain bytes_per_line bytes, each byte is represented using uppercase two digit hex. There will be a space between bytes. And at end of line or end of buffer it will print a newline. If bytes_per_line is set to 0, then it will not print new_line. Try for yourself.
For simple usage I made a function that encodes the input string (binary data):
/* 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;
}
Usage:
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;
Based on Yannuth's answer but simplified.
Here, length of dest[] is implied to be twice of len, and its allocation is managed by the caller.
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];
}
}
I know this question already has an answer but I think my solution could help someone.
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].
If you want to store the hex values in a char * string, you can use snprintf. You need to allocate space for all the printed characters, including the leading zeros and colon.
Expanding on Mark's answer:
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
So now str_buf will contain the hex string.
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);
}