Can anyone suggest means of converting a byte array to ASCII in C? Or converting byte array to hex and then to ASCII?
[04/02][Edited]: To rephrase it, I wish to convert bytes to hex and store the converted hex values in a data structure. How should go about it?
Regards,
darkie
Well, if you interpret an integer as a char in C, you'll get that ASCII character, as long as it's in range.
int i = 97;
char c = i;
printf("The character of %d is %c\n", i, c);
Prints:
The character of 97 is a
Note that no error checking is done - I assume 0 <= i < 128 (ASCII range).
Otherwise, an array of byte values can be directly interpreted as an ASCII string:
char bytes[] = {97, 98, 99, 100, 101, 0};
printf("The string: %s\n", bytes);
Prints:
The string: abcde
Note the last byte: 0, it's required to terminate the string properly. You can use bytes as any other C string, copy from it, append it to other strings, traverse it, print it, etc.
First of all you should take some more care on the formulation of your questions. It is hard to say what you really want to hear. I think you have some binary blob and want it in a human readable form, e.g. to dump it on the screen for debugging. (I know I'm probably misinterpreting you here).
You can use snprintf(buf, sizeof(buf), "%.2x", byte_array[i]) for example to convert a single byte in to the hexadecimal ASCII representation. Here is a function to dump a whole memory region on the screen:
void
hexdump(const void *data, int size)
{
const unsigned char *byte = data;
while (size > 0)
{
size--;
printf("%.2x ", *byte);
byte++;
}
}
Char.s and Int.s are stored in binary in C. And can generally be used in place of each other when working in the ASCII range.
int i = 0x61;
char x = i;
fprintf( stdout, "%c", x );
that should print 'a' to the screen.
Related
I was trying to make this int to char program. The +'0' in the do while loop wont convert the int value to ascii, whereas, +'0' in main is converting. I have tried many statements, but it won't work in convert() .
#include<stdio.h>
#include<string.h>
void convert(int input,char s[]);
void reverse(char s[]);
int main()
{
int input;
char string[5];
//prcharf("enter int\n");
printf("enter int\n");
scanf("%d",&input);
convert(input,string);
printf("Converted Input is : %s\n",string);
int i=54;
printf("%c\n",(i+'0')); //This give ascii char value of int
printf("out\n");
}
void convert(int input,char s[])
{
int sign,i=0;
char d;
if((sign=input)<0)
input=-input;
do
{
s[i++]='0'+input%10;//but this gives int only
} while((input/=10)>0);
if(sign<0)
s[i++]='-';
s[i]=EOF;
reverse(s);
}
void reverse(char s[])
{
int i,j;
char temp;
for(i=0,j=strlen(s)-1;i<j;i++,j--)
{
temp=s[i];
s[i]=s[j];
s[j]=temp;
}
}
Output screenshot
Code screenshot
The +'0' in the do while loop wont convert the int value to ascii
Your own screenshot shows otherwise (assuming an ASCII-based terminal).
Your code printed 56, so it printed the bytes 0x35 and 0x36, so string[0] and string[1] contain 0x35 and 0x36 respectively, and 0x35 and 0x36 are the ASCII encodings of 5 and 6 respectively.
You can also verify this by printing the elements of string individually.
for (int i=0; string[i]; ++i)
printf("%02X ", string[i]);
printf("\n");
I tried your program and it is working for the most part. I get some goofy output because of this line:
s[i]=EOF;
EOF is a negative integer macro that represents "End Of File." Its actual value is implementation defined. It appears what you actually want is a null terminator:
s[i]='\0';
That will remove any goofy characters in the output.
I would also make that string in main a little bigger. No reason we couldn't use something like
char string[12];
I would use a bare minimum of 12 which will cover you to a 32 bit INT_MAX with sign.
EDIT
It appears (based on all the comments) you may be actually trying to make a program that simply outputs characters using numeric ascii values. What the convert function actually does is converts an integer to a string representation of that integer. For example:
int num = 123; /* Integer input */
char str_num[12] = "123"; /* char array output */
convert is basically a manual implementation of itoa.
If you are trying to simply output characters given ascii codes, this is a much simpler program. First, you should understand that this code here is a mis-interpretation of what convert was trying to do:
int i=54;
printf("%c\n",(i+'0'));
The point of adding '0' previously, was to convert single digit integers to their ascii code version. For reference, use this: asciitable. For example if you wanted to convert the integer 4 to a character '4', you would add 4 to '0' which is ascii code 48 to get 52. 52 being the ascii code for the character '4'. To print out the character that is represented by ascii code, the solution is much more straightforward. As others have stated in the comments, char is a essentially a numeric type already. This will give you the desired behavior:
int i = 102 /* The actual ascii value of 'f' */
printf("%c\n", i);
That will work, but to be safe that should be cast to type char. Whether or not this is redundant may be implementation defined. I do believe that sending incorrect types to printf is undefined behavior whether it works in this case or not. Safe version:
printf("%c\n", (char) i);
So you can write the entire program in main since there is no need for the convert function:
int main()
{
/* Make initialization a habit */
int input = 0;
/* Loop through until we get a value between 0-127 */
do {
printf("enter int\n");
scanf("%d",&input);
} while (input < 0 || input > 127);
printf("Converted Input is : %c\n", (char)input);
}
We don't want anything outside of 0-127. char has a range of 256 bits (AKA a byte!) and spans from -127 to 127. If you wanted literal interpretation of higher characters, you could use unsigned char (0-255). This is undesirable on the linux terminal which is likely expecting UTF-8 characters. Values above 127 will be represent portions of multi-byte characters. If you wanted to support this, you will need a char[] and the code will become a lot more complex.
I'm not familiar with C at all so this might be a simple problem to solve. I'm trying to take an input char* array of binary character sequences, ex. "0100100001101001", and output its relative string ("Hi"). The problem I'm having is coming up with a way to split the input into seperate strings of length 8 and then convert them individually to ulimately get the full output string.
char* binaryToString(char* b){
char binary[8];
for(int i=0; i<8; ++i){
binary[i] = b[i];
}
printf("%s", binary);
}
I'm aware of how to convert 8-bit into its character, I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
Any help is appreciated... thanks!
From what I can tell, your binaryToString() function does not do what you'd want it to. The print statement just prints the first eight characters from the address pointed to by char* b.
Instead, you can convert the string of 8 bits to an integer, utilizing a standard C function strtol(). There's no need to convert any further, because binary, hex, decimal, etc, are all just representations of the same data! So once the string is converted to a long, you can use that value to represent an ASCII character.
Updating the implementation (as below), you can then leverage it to print a whole sequence.
#include <stdio.h>
#include <string.h>
void binaryToString(char* input, char* output){
char binary[9] = {0}; // initialize string to 0's
// copy 8 bits from input string
for (int i = 0; i < 8; i ++){
binary[i] = input[i];
}
*output = strtol(binary,NULL,2); // convert the byte to a long, using base 2
}
int main()
{
char inputStr[] = "01100001011100110110010001100110"; // "asdf" in ascii
char outputStr[20] = {0}; // initialize string to 0's
size_t iterations = strlen(inputStr) / 8; // get the # of bytes
// convert each byte into an ascii value
for (int i = 0; i < iterations; i++){
binaryToString(&inputStr[i*8], &outputStr[i]);
}
printf("%s", outputStr); // print the resulting string
return 0;
}
I compiled this and it seems to work fine. Of course, this can be done cleaner and safer, but this should help you get started.
I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
You can use strncpy() to copy the sequence of '0' and '1' in a chunk of 8 characters at a time from the input string, something like this:
//get the size of input string
size_t len = strlen(b);
//Your input array of '0' and '1' and every sequence of 8 bytes represents a character
unsigned int num_chars = len/8;
//Take a temporary pointer and point it to input string
const char *tmp = b;
//Now copy the 8 chars from input string to buffer "binary"
for(int i=0; i<num_chars; ++i){
strncpy(binary, tmp+(i*8), 8);
//do your stuff with the 8 chars copied from input string to "binary" buffer
}
Maybe this can help. I didnt compile it but there is the idea. You can loop every 8 bit separately with while loop. And assign 8 bit to binary array with for loop. After that send this binary array to convert8BitToChar function to get letter equivalent of 8 bit. Then append the letter to result array. I'm not writing c for 3 year if there is mistakes sorry about that. Here pseudo code.
char* binaryToString(char* b){
char* result = malloc(sizeof(256*char));
char binary[8];
int nextLetter = 0;
while (b[nextLetter*8] != NULL) { // loop every 8 bit
for(int i=0; i<8; ++i){
binary[i] = b[nextLetter*8+i];
}
result[nextLetter] = 8bitToChar(binary));// convert 8bitToChar and append yo result
nextLetter++;
}
result[nextLetter] = '\0';
return result;
}
I would convert myString "100.200.300.400" to byte array [4].
I'm a "bit" confused, this is right or need i to use a foreach for reading a single number?
String myString = "100.200.300.400";
byte myByteArray[4];
myString.getBytes(myByteArray,4);
Finally I want to print to the array to serial. This should be right.
for (i=0; i<4; i++) {
Serial.print(myByteArray[i]);
Serial.print("."); //delimiter
}
Were I am going wrong? I got 49,48,48,0 !
If you are trying to get from a string like "100.150.200.250" to a byte array like { 100, 150, 200, 250 }, you need to extract the string representation for each number and convert (parse) them into a binary representation before storing them in the byte array.
The way you are trying to do this, you are just converting the first four bytes from the string, i.e. "100.", to the binary representation of each character, which turns out to be { 49, 48, 48, 0 }. You can look that up in an ASCII table.
Also remember that, as you are storing this on a byte array, it will only support values from 0 to 255.
As you are programming on small microcontroller, I would advise against using the String class. You might run into trouble when your programs get bigger and you start using lots of strings. Try to learn how to use character arrays instead and you will avoid running into memory issues. Remember the Arduino has just 2KB of RAM!
Here is a function you can use to make that conversion using the strtoul() function:
void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) {
for (int i = 0; i < maxBytes; i++) {
bytes[i] = strtoul(str, NULL, base); // Convert byte
str = strchr(str, sep); // Find next separator
if (str == NULL || *str == '\0') {
break; // No more separators, exit
}
str++; // Point to next character after separator
}
}
You can then call it like this to convert an IP address (base 10):
const char* ipStr = "50.100.150.200";
byte ip[4];
parseBytes(ipStr, '.', ip, 4, 10);
Or like this to convert a MAC address (base 16):
const char* macStr = "90-A2-AF-DA-14-11";
byte mac[6];
parseBytes(macStr, '-', mac, 6, 16);
You could also use sscanf, and by the way detect invalid inputs using its return value:
byte ip[4];
if (sscanf(mString.c_str(), "%hhu.%hhu.%hhu.%hhu", ip, ip+1, ip+2, ip+3) != 4) {
Serial.print("invalid IP: ");
Serial.println(mString);
}
However, sscanf may not be implemented in the library for all boards, for example on esp8266 it's yet to be released in version 2.4.0.
Also, the %hhu specifier for unsigned char may be not supported in some versions, but you can use %u, read it to an unsigned long and check if the value isn't greater than 255.
Here's my problem, I have a byte struct that looks like these:
struct machinecode{
char byte1[2];
char byte2[2];
char byte3[2];
char byte4[2];
char byte5[2];
char byte6[2];
char byte7[2];
char byte8[2];
char byte9[2];
};
struct machinecode WRITEME[500];
now, these collection of 2byte chars or strings are formatted in hex bytes that looks like these for example:
byte1 = "01"
byte2 = "C0"
char bytes are assigned like these:
...
char * returner
...
strncpy(WRITEME[index].byte1, "00", 2);
strncpy(WRITEME[index].byte2, returner, 2);
my printing code looks like these:
while(counter < max){
...
else if(prog_counter[counter2] == 2){
fprintf(w, ???, WRITEME[counter].byte1);
fprintf(w, ???, WRITEME[counter].byte2);
}
...
}
Now I wanted this to print string as hex bytes, what kind of formatting(???) do I need to use for fprintf? or do I need to convert this hex byte string first to int before fprinting them?
I tried "%x", "%X" but they doesn't work.
EDIT:
I would like to add that I'm making a .com executable file, so I need to print them as hex bytes.
Revised answer
You say "I'm making a .COM executable file so I need to print them as hex bytes". The immediate response is then "Why on earth are you converting the values into a pair of bytes in the first place?" You'll have to convert them back to a single byte and then write that byte using the %c notation. One way, probably not the best way, to do that is:
static const char hexits[] = "0123456789ABCDEF";
static inline int byte_from_hex(const char *hex)
{
assert(isxdigit(hex[0]) && isxdigit(hex[1]));
int b1 = strchr(hexits, toupper((unsigned char)hex[0])) - hexits;
int b2 = strchr(hexits, toupper((unsigned char)hex[1])) - hexits;
return b1 * 16 + b2;
}
fprintf(w, "%c", byte_from_hex(WRITEME[counter].byte1);
But it would be far simpler not to convert to a string in the first place.
Original answer
Because your data is not null terminated, you need to use a length in the conversion specifications, as specified in the fprintf() manual page:
%.2s
This means print at most 2 characters from the character array.
fprintf(w, "%.2s", WRITEME[counter].byte1);
This assumes you did something like:
WRITEME[counter].byte1[0] = '0';
WRITEME[counter].byte2[1] = '1';
or:
memmove(WRITEME[counter].byte1, "01", sizeof(WRITEME[counter].byte1);
or (as the comments showed you did):
strncpy(WRITEME[counter].byte1, "01", 2); // or sizeof(WRITEME[counter].byte1)
and that you did not do something like:
sprintf(WRITEME[counter].byte1, "%2X", byte_value);
and that you did not do something like:
strcpy(WRITEME[counter].byte1, "01");
Here's how I fix this.
First I used Jonathan's solution of using sscanf and printf.
Then I encountered a weird bug that puts random "0d" on my file.
The solution was to open and write the file in binary mode.
w = fopen( filename , "wb" );
Hope this helps other users in the future
I have a char array with data from a text file and I need to convert it to hexadecimal format.
Is there such a function for C language.
Thank you in advance!
If I understand the question correctly (no guarantees there), you have a text string representing a number in decimal format ("1234"), and you want to convert it to a string in hexadecimal format ("4d2").
Assuming that's correct, your best bet will be to convert the input string to an integer using either sscanf() or strtol(), then use sprintf() with the %x conversion specifier to write the hex version to another string:
char text[] = "1234";
char result[SIZE]; // where SIZE is big enough to hold any converted value
int val;
val = (int) strtol(text, NULL, 0); // error checking omitted for brevity
sprintf(result, "%x", val);
I am assuming that you want to be able to display the hex values of individual byes in your array, sort of like the output of a dump command. This is a method of displaying one byte from that array.
The leading zero on the format is needed to guarantee consistent width on output.
You can upper or lower case the X, to get upper or lower case representations.
I recommend treating them as unsigned, so there is no confusion about sign bits.
unsigned char c = 0x41;
printf("%02X", c);
You can use atoi and sprintf / snprintf. Here's a simple example.
char* c = "23";
int number = atoi(c);
snprintf( buf, sizeof(buf), "%x", number );