I have tried out many ideas from SO. One of them worked (output was DEC 49 for HEX 31) when I tested it in here onlinegdb.
But, when I implemented it in my application, it didn't produce same results. (output was 31 for 31 again).
The idea is to use a string value (full of HEX pairs);
An example; 313030311b5b324a1b5b324a534f495f303032371b
I need to convert each integer pair (HEX) into equivalence decimal value.
e.g.
HEX => DEC
31 => 49
30 => 48
I will then send the DEC value using UART value by value.
The code I test the behavior is below and here;
But, it doesn't have to be that code, I am open to all suggestions as long as it does the job.
#include <stdio.h>
int isHexaDigit(char p) {
return (( '0' <= p && p <= '9' ) || ( 'A' <= p && p <= 'F'));
}
int main(int argc, char** argv)
{
char * str = "31";
char t[]="31";
char* p = t;
char val[3]; // 2 hexa digit
val[2] = 0; //and the final \0 for a string
int number;
while (isHexaDigit(*p) && isHexaDigit(*(p+1))) {
val[0] = *p;
val[1] = *(p+1);
sscanf(val,"%X", &number); // <---- Read hexa string into number
printf("\nNum=%i",number); // <---- Display number to decimal.
p++;
//p++;
if (!*p) break;
p++;
}
return 0;
}
EDIT
I minimized the code.
Odd-length string is ignored for the time being.
The code sends out the data byte by byte. In the terminal application,
I get the values as HEX, e.g. HEX 31 instead of DEC 49. They are actually same. But, a device I use requires DEC 49 version of the value (which is ASCII = 1)
Any pointer highly appreciated.
You can use strtol function to convert your hex string to binary and then convert it to a decimal string in a single line:
snprintf(str_dec, 4, "%ld", strtol(str_hex, NULL, 16));
Your code becomes:
#include <stdio.h>
#include <stdlib.h>
int isHexaDigit(char p) {
return (( '0' <= p && p <= '9' ) || ( 'A' <= p && p <= 'F'));
}
int main(int argc, char** argv)
{
char * str = "31";
char t[]="31";
char* p = t;
char str_hex[3] = {0,};
char str_dec[4] = {0,};
while (isHexaDigit(*p) && isHexaDigit(*(p+1))) {
str_hex[0] = *p;
str_hex[1] = *(p+1);
/* Convert hex string to decimal string */
snprintf(str_dec, 4, "%ld", strtol(str_hex, NULL, 16));
printf("str_dec = %s\n", str_dec);
/* Send the decimal string over UART1 */
if (str_dec[0]) UART1_Write(str_dec[0]);
if (str_dec[1]) UART1_Write(str_dec[1]);
if (str_dec[2]) UART1_Write(str_dec[2]);
/* Reset str_dec variable */
str_dec[0] = 0;
str_dec[1] = 0;
str_dec[2] = 0;
p++;
if (!*p) break;
p++;
}
return 0;
}
Related
I created this function to convert a number 'd' in base 10 to a number x in base 'b', unfortunately the function does not print, could someone help me?
// I don't understand why it doesn't print me the encode
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 20
// the function created to convert a number 'd' in base 10 to a number in base 'b'
char *encode(unsigned int d, unsigned char b){
if(b<2||b>16) return NULL;
char * resto = calloc (SIZE, sizeof(char));
int i=1;
while(d>0){//rimanenza d%b
char rimanenza = d%b ;
d = d/b;
if (b>10 && b<=16){//if the base is between 10 and 16 'rimanenza' can't be a number
if (rimanenza == 10) rimanenza = 'A';
if (rimanenza == 11) rimanenza = 'B';
if (rimanenza == 12) rimanenza = 'C';
if (rimanenza == 13) rimanenza = 'D';
if (rimanenza == 14) rimanenza = 'E';
if (rimanenza == 15) rimanenza = 'F';
}// save into resto from the end
resto [SIZE - i] = rimanenza;
i++;
}
return resto ;
}
int main (){
unsigned int d = 126;
unsigned char b = 3;
char *encoded = encode (d,b);
printf ("%u in base %u = %s\n",d,b,encoded);
free(encoded);
}
At least these problems:
Digit not converted to correct character when rimanenza < 10
When rimanenza is in the [0...9] range, convert it to characters ['0'...'9'].
rimanenza += '0';
while(d>0){ fails to form "0" when d originally 0.
Return wrong offset
return resto ; fails to return the beginning of the populated part of resto[].
More like:
// return resto ;
return memmove(resto, &resto[SIZE - i - 1], SIZE - i);
Fails to test if calloc() failed
Size too small
#define SIZE 20 is insufficient for encode(UINT_MAX, 2). #M Oehm
Lack of trailing null character
Code needs a '\0' after all the characters to be a string.
Code allocation is not sized to the data
Consider only allocating what is needed.
Untested repairs
#include <limits.h>
#define ENCODE_SZ (sizeof (unsigned) * CHAR_BIT + 1) // Size buffer to base 2 worst case
char* encode(unsigned d, unsigned b) {
if (b < 2 || b > 16) {
return NULL;
}
char buffer[ENCODE_SZ];
char *p = &buffer[ENCODE_SZ - 1]; // Point to last array element.
*p = '\0'; // Terminate array with a null character.
// Use a do loop to make sure code assigns at least 1 character.
do {
unsigned digit = d % b;
// Look-up character;
char ch = "0123456789ABCDEF"[digit];
p--;
*p = ch;
d /= b;
} while (d > 0);
// Determine string length
unsigned length = &buffer[ENCODE_SZ - 1] - p;
unsigned size = length + 1;
char *resto = malloc(size);
if (resto == NULL) {
return NULL;
}
// Copy and return.
return strcpy(resto, p);
}
I'm trying to write my first kernel module so I'm not able to include libraries for atoi, strtol, etc. How can I convert a string to int without these built-in functions? I tried:
int num;
num = string[0] - '0';
which works for the first character, but if I remove the [0] to try and convert the full string it gives me a warning: assignment makes integer from pointer without a cast. So what do I do?
When creating your own string to int function, make sure you check and protect against overflow. For example:
/* an atoi replacement performing the conversion in a single
pass and incorporating 'err' to indicate a failed conversion.
passing NULL as error causes it to be ignored */
int strtoi (const char *s, unsigned char *err)
{
char *p = (char *)s;
int nmax = (1ULL << 31) - 1; /* INT_MAX */
int nmin = -nmax - 1; /* INT_MIN */
long long sum = 0;
char sign = *p;
if (*p == '-' || *p == '+') p++;
while (*p >= '0' && *p <= '9') {
sum = sum * 10 - (*p - '0');
if (sum < nmin || (sign != '-' && -sum > nmax)) goto error;
p++;
}
if (sign != '-') sum = -sum;
return (int)sum;
error:
fprintf (stderr, "strtoi() error: invalid conversion for type int.\n");
if (err) *err = 1;
return 0;
}
You can't remove the [0]. That means that you are subtracting '0' from the pointer string, which is meaningless. You still need to dereference it:
num = string[i] - '0';
A string is an array of characters, represented by an address (a.k.a pointer).
An pointer has an value that might look something like 0xa1de2bdf. This value tells me where the start of the array is.
You cannot subtract a pointer type with a character type (e.g 0xa1de2bdf - 'b' does not really make sense).
To convert a string to a number, you could try this:
//Find the length of the string
int len = 0;
while (str[len] != '\0') {
len++;
}
//Loop through the string
int num = 0, i = 0, digit;
for (i=0; i<len; i++) {
//Extract the digit
digit = ing[i] - '0';
//Multiply the digit with its correct position (ones, tens, hundreds, etc.)
num += digit * pow(10, (len-1)-i);
}
Of course if you are not allowed to use math.h library, you could write your own pow(a,b) function which gives you the value of a^b.
int mypowfunc(int a, int b) {
int i=0, ans=1;
//multiply the value a for b number of times
for (i=0; i<b; i++) {
ans *= a;
}
return ans;
}
I have written the code above in a way that is simple to understand. It assumes that your string has a null character ('\0') right behind the last useful character (which is good practice).
Also, you might want to check that the string is actually a valid string with only digits (e.g '0', '1', '2', etc.). You could do this by including an if... else.. statement while looping through the string.
In modern kernels you want to use kstrto*:
http://lxr.free-electrons.com/source/include/linux/kernel.h#L274
274 /**
275 * kstrtoul - convert a string to an unsigned long
276 * #s: The start of the string. The string must be null-terminated, and may also
277 * include a single newline before its terminating null. The first character
278 * may also be a plus sign, but not a minus sign.
279 * #base: The number base to use. The maximum supported base is 16. If base is
280 * given as 0, then the base of the string is automatically detected with the
281 * conventional semantics - If it begins with 0x the number will be parsed as a
282 * hexadecimal (case insensitive), if it otherwise begins with 0, it will be
283 * parsed as an octal number. Otherwise it will be parsed as a decimal.
284 * #res: Where to write the result of the conversion on success.
285 *
286 * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
287 * Used as a replacement for the obsolete simple_strtoull. Return code must
288 * be checked.
289 */
This function skips leading and trailing whitespace, handles one optional + / - sign, and returns 0 on invalid input,
// Convert standard null-terminated string to an integer
// - Skips leading whitespaces.
// - Skips trailing whitespaces.
// - Allows for one, optional +/- sign at the front.
// - Returns zero if any non-+/-, non-numeric, non-space character is encountered.
// - Returns zero if digits are separated by spaces (eg "123 45")
// - Range is checked against Overflow/Underflow (INT_MAX / INT_MIN), and returns 0.
int StrToInt(const char* s)
{
int minInt = 1 << (sizeof(int)*CHAR_BIT-1);
int maxInt = -(minInt+1);
char* w;
do { // Skip any leading whitespace
for(w=" \t\n\v\f\r"; *w && *s != *w; ++w) ;
if (*s == *w) ++s; else break;
} while(*s);
int sign = 1;
if ('-' == *s) sign = -1;
if ('+' == *s || '-' == *s) ++s;
long long i=0;
while('0' <= *s && *s <= '9')
{
i = 10*i + *s++ - '0';
if (sign*i < minInt || maxInt < sign*i)
{
i = 0;
break;
}
}
while (*s) // Skip any trailing whitespace
{
for(w=" \t\n\v\f\r"; *w && *s != *w; ++w) ;
if (*w && *s == *w) ++s; else break;
}
return (int)(!*s*sign*i);
}
" not able to include libraries" --> Unclear if code is allowed access to INT_MAX, INT_MIN. There is no way to determine the minimum/maximum signed integer in a completely portable fashion without using the language provided macros like INT_MAX, INT_MIN.
Use INT_MAX, INT_MIN is available. Else we could guess the char width is 8. We could guess there are no padding bits. We could guess that integers are 2's complement. With these reasonable assumptions, minimum and maximum are defined below.
Note: Shifting into the sign bit is undefined behavior (UB), so don't do that.
Let us add another restriction: make a solution that works for any signed integer from signed char to intmax_t. This disallows code from using a wider type, as there may not be a wider type.
typedef int Austin_int;
#define Austin_INT_MAXMID ( ((Austin_int)1) << (sizeof(Austin_int)*8 - 2) )
#define Austin_INT_MAX (Austin_INT_MAXMID - 1 + Austin_INT_MAXMID)
#define Austin_INT_MIN (-Austin_INT_MAX - 1)
int Austin_isspace(int ch) {
const char *ws = " \t\n\r\f\v";
while (*ws) {
if (*ws == ch) return 1;
ws++;
}
return 0;
}
// *endptr points to where parsing stopped
// *errorptr indicates overflow
Austin_int Austin_strtoi(const char *s, char **endptr, int *errorptr) {
int error = 0;
while (Austin_isspace(*s)) {
s++;
}
char sign = *s;
if (*s == '-' || *s == '+') {
s++;
}
Austin_int sum = 0;
while (*s >= '0' && *s <= '9') {
int ch = *s - '0';
if (sum <= Austin_INT_MIN / 10 &&
(sum < Austin_INT_MIN / 10 || -ch < Austin_INT_MIN % 10)) {
sum = Austin_INT_MIN;
error = 1;
} else {
sum = sum * 10 - ch;
}
s++;
}
if (sign != '-') {
if (sum < -Austin_INT_MAX) {
sum = Austin_INT_MAX;
error = 1;
} else {
sum = -sum;
}
}
if (endptr) {
*endptr = (char *) s;
}
if (errorptr) {
*errorptr = error;
}
return sum;
}
The above depends on C99 or later in the Austin_INT_MIN Austin_INT_MIN % 10 part.
This is the cleanest and safest way I could come up with
int str_to_int(const char * str, size_t n, int * int_value) {
int i;
int cvalue;
int value_muliplier = 1;
int res_value = 0;
int neg = 1; // -1 for negative and 1 for whole.
size_t str_len; // String length.
int end_at = 0; // Where loop should end.
if (str == NULL || int_value == NULL || n <= 0)
return -1;
// Get string length
str_len = strnlen(str, n);
if (str_len <= 0)
return -1;
// Is negative.
if (str[0] == '-') {
neg = -1;
end_at = 1; // If negative 0 item in 'str' is skipped.
}
// Do the math.
for (i = str_len - 1; i >= end_at; i--) {
cvalue = char_to_int(str[i]);
// Character not a number.
if (cvalue == -1)
return -1;
// Do the same math that is down below.
res_value += cvalue * value_muliplier;
value_muliplier *= 10;
}
/*
* "436"
* res_value = (6 * 1) + (3 * 10) + (4 * 100)
*/
*int_value = (res_value * neg);
return 0;
}
int char_to_int(char c) {
int cvalue = (int)c;
// Not a number.
// 48 to 57 is 0 to 9 in ascii.
if (cvalue < 48 || cvalue > 57)
return -1;
return cvalue - 48; // 48 is the value of zero in ascii.
}
I cannot seem to get my output to work correctly. I want to make it so that the last remainder in parenthesis is lined up perfectly in a column following the first line's spacing. I have most of the output right except for this last part and it has to be exactly the way my professor wants it.
The best I've been able to come up with is EDITED:
Marcus Lorenzana
314156 = 19634 * 16 + 12 (C)
19634 = 1227 * 16 + 2 (2)
1227 = 76 * 16 + 11 (B)
76 = 4 * 16 + 12 (C)
4 = 0 * 16 + 4 (4)
0x4CB2C
This is the output I want:
Marcus Lorenzana
314156 = 19634 * 16 + 12 (C)
19634 = 1227 * 16 + 2 (2)
1227 = 76 * 16 + 11 (B)
76 = 4 * 16 + 12 (C)
4 = 0 * 16 + 4 (4)
0x4CB2C
But as you can see it the output is not exactly correct.
Here is my program EDITED:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER 50
static int base = 16;
int main(int argc, char * argv[]) {
printf("Marcus Lorenzana\n");
if (argc == 2) {
char hexstr[] = "0123456789ABCDEF";
int i = 0;
long long oldresult;
int remainder;
char remainders[BUFFER];
char w_num[BUFFER];
long long value = atoll(argv[1]);
//Get width of original number for formatting purposes
int vwidth = strlen(argv[1]);
char oldwidth[BUFFER];
//Convert the decimal to hexadecimal
while(value != 0) {
oldresult=value;
remainder = value%base;
value = value/base;
//Store the remainder in an array for later use
remainders[i]=hexstr[remainder];
char line[BUFFER];
//Get length of line for formatting purposes
int w = sprintf(line,"%*lld = %-*lld * %2d + %2d", \
vwidth,oldresult,vwidth,value,base,remainder);
printf("%s (%c)\n", line,hexstr[remainder]);
i++;
}
//Print the the hexadecimal number
int x = i;
printf("0x");
while(x > 0) {
printf("%c",remainders[--x]);
}
printf("\n");
} else {
printf("Error: Wrong arguments\n");
return 1;
}
return 0;
}
Modify based on your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER 50
static int base = 16;
int main(int argc, char * argv[]) {
printf("Marcus Lorenzana\n");
if (argc == 2) {
char hexstr[] = "0123456789ABCDEF";
int i = 0;
long long oldresult;
int remainder;
char remainders[BUFFER];
char w_num[BUFFER];
long long value = atoll(argv[1]);
//Get width of original number for formatting purposes
int vwidth = strlen(argv[1]);
char oldwidth[BUFFER];
int wMax = 0;
//Convert the decimal to hexadecimal
while(value != 0) {
oldresult=value;
remainder = value%base;
value = value/base;
//Store the remainder in an array for later use
remainders[i]=hexstr[remainder];
char line[BUFFER];
//Get length of line for formatting purposes
int w = sprintf(line,"%*lld = %-lld * %2d + %-2d", \
vwidth,oldresult,value,base,remainder);
wMax = w > wMax ? w:wMax;
printf("%s %*s(%c)\n", line,wMax-w,"",hexstr[remainder]);
i++;
}
//Print the the hexadecimal number
int x = i;
printf("0x");
while(x > 0) {
printf("%c",remainders[--x]);
}
printf("\n");
} else {
printf("Error: Wrong arguments\n");
return 1;
}
return 0;
}
Your idea to print the right-hand side to a temporary string is good, but for the output you want, you should just print the stuff to thr right of the equals sign to that string. Also, because you don't want the operands lined up, strip all formatting information, i.e. the widths, from the string.
snprintf(line, BUFFER, "%lld * %d + %d", value, base, remainder);
printf("%*lld = %*s (%c)\n", vwidth, oldresult,
-(vwidth + 10), line, hexstr[remainder]);
The width of the rhs is calculated based on the initial length of the number, vwidth plus two times two for the numbers plus two times three for the operands with surrounding spaces. The width has to be negative, because you want the RHS to be left-aligned and passed with spaces to the right.
If you let printf do the padding, there's no need to store the string length from the sprintf call, w.
I have a char array say char value []={'0','2','0','c','0','3'};
I want to convert this into a byte array like unsigned char val[]={'02','0c','03'}
This is in an embedded application so i can't use string.h functions. How can i do this?
Sicne you talk about an embedded application I assume that you want to save the numbers as values and not as strings/characters. So if you just want to store your character data as numbers (for example in an integer), you can use sscanf.
This means you could do something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
uint8 dest_val[3]; // We want to save 3 numbers
for(int i = 0; i<3; i++)
{
sscanf(&source_val[i*2],"%x%x",&dest_val[i]); // Everytime we read two chars --> %x%x
}
// Now dest_val contains 0x0A, 0x03 and 0xB7
However if you want to store it as a string (like in your example), you can't use unsigned char
since this type is also just 8-Bit long, which means it can only store one character. Displaying 'B3' in a single (unsigned) char does not work.
edit: Ok according to comments, the goal is to save the passed data as a numerical value. Unfortunately the compiler from the opener does not support sscanf which would be the easiest way to do so. Anyhow, since this is (in my opinion) the simplest approach, I will leave this part of the answer at it is and try to add a more custom approach in this edit.
Regarding the data type, it actually doesn't matter if you have uint8. Even though I would advise to use some kind of integer data type, you can also store your data into an unsigned char. The problem here is, that the data you get passed, is a character/letter, that you want to interpret as a numerical value. However, the internal storage of your character differs. You can check the ASCII Table, where you can check the internal values for every character.
For example:
char letter = 'A'; // Internally 0x41
char number = 0x61; // Internally 0x64 - represents the letter 'a'
As you can see there is also a differnce between upper an lower case.
If you do something like this:
int myVal = letter; //
myVal won't represent the value 0xA (decimal 10), it will have the value 0x41.
The fact you can't use sscanf means you need a custom function. So first of all we need a way to conver one letter into an integer:
int charToInt(char letter)
{
int myNumerical;
// First we want to check if its 0-9, A-F, or a-f) --> See ASCII Table
if(letter > 47 && letter < 58)
{
// 0-9
myNumerical = letter-48;
// The Letter "0" is in the ASCII table at position 48 -> meaning if we subtract 48 we get 0 and so on...
}
else if(letter > 64 && letter < 71)
{
// A-F
myNumerical = letter-55
// The Letter "A" (dec 10) is at Pos 65 --> 65-55 = 10 and so on..
}
else if(letter > 96 && letter < 103)
{
// a-f
myNumerical = letter-87
// The Letter "a" (dec 10) is at Pos 97--> 97-87 = 10 and so on...
}
else
{
// Not supported letter...
myNumerical = -1;
}
return myNumerical;
}
Now we have a way to convert every single character into a number. The other problem, is to always append two characters together, but this is rather easy:
int appendNumbers(int higherNibble, int lowerNibble)
{
int myNumber = higherNibble << 4;
myNumber |= lowerNibbler;
return myNumber;
// Example: higherNibble = 0x0A, lowerNibble = 0x03; -> myNumber 0 0xA3
// Of course you have to ensure that the parameters are not bigger than 0x0F
}
Now everything together would be something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
int dest_val[3]; // We want to save 3 numbers
int temp_low, temp_high;
for(int i = 0; i<3; i++)
{
temp_high = charToInt(source_val[i*2]);
temp_low = charToInt(source_val[i*2+1]);
dest_val[i] = appendNumbers(temp_high , temp_low);
}
I hope that I understood your problem right, and this helps..
If you have a "proper" array, like value as declared in the question, then you loop over the size of it to get each character. If you're on a system which uses the ASCII alphabet (which is most likely) then you can convert a hexadecimal digit in character form to a decimal value by subtracting '0' for digits (see the linked ASCII table to understand why), and subtracting 'A' or 'a' for letters (make sure no letters are higher than 'F' of course) and add ten.
When you have the value from the first hexadeximal digit, then convert the second hexadecimal digit the same way. Multiply the first value by 16 and add the second value. You now have single byte value corresponding to two hexadecimal digits in character form.
Time for some code examples:
/* Function which converts a hexadecimal digit character to its integer value */
int hex_to_val(const char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0'; /* Simple ASCII arithmetic */
else if (ch >= 'a' && ch <= 'f')
return 10 + ch - 'a'; /* Because hex-digit a is ten */
else if (ch >= 'A' && ch <= 'F')
return 10 + ch - 'A'; /* Because hex-digit A is ten */
else
return -1; /* Not a valid hexadecimal digit */
}
...
/* Source character array */
char value []={'0','2','0','c','0','3'};
/* Destination "byte" array */
char val[3];
/* `i < sizeof(value)` works because `sizeof(char)` is always 1 */
/* `i += 2` because there is two digits per value */
/* NOTE: This loop can only handle an array of even number of entries */
for (size_t i = 0, j = 0; i < sizeof(value); i += 2, ++j)
{
int digit1 = hex_to_val(value[i]); /* Get value of first digit */
int digit2 = hex_to_val(value[i + 1]); /* Get value of second digit */
if (digit1 == -1 || digit2 == -1)
continue; /* Not a valid hexadecimal digit */
/* The first digit is multiplied with the base */
/* Cast to the destination type */
val[j] = (char) (digit1 * 16 + digit2);
}
for (size_t i = 0; i < 3; ++i)
printf("Hex value %lu = %02x\n", i + 1, val[i]);
The output from the code above is
Hex value 1 = 02
Hex value 2 = 0c
Hex value 3 = 03
A note about the ASCII arithmetic: The ASCII value for the character '0' is 48, and the ASCII value for the character '1' is 49. Therefore '1' - '0' will result in 1.
It's easy with strtol():
#include <stdlib.h>
#include <assert.h>
void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
/** size 3 is important to make sure tmp is \0-terminated and
the initialization guarantees that the array is filled with zeros */
char tmp[3] = "";
while (n--) {
tmp[0] = *src++;
tmp[1] = *src++;
*dest++ = strtol(tmp, NULL, 16);
}
}
int main(void)
{
unsigned char d[3];
parse_bytes(d, "0a1bca", 3);
assert(d[0] == 0x0a);
assert(d[1] == 0x1b);
assert(d[2] == 0xca);
return EXIT_SUCCESS;
}
If that is not available (even though it is NOT from string.h), you could do something like:
int ctohex(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
}
switch (c) {
case 'a':
case 'A':
return 0xa;
case 'b':
case 'B':
return 0xb;
/**
* and so on
*/
}
return -1;
}
void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
while (n--) {
*dest = ctohex(*src++) * 16;
*dest++ += ctohex(*src++);
}
}
Assuming 8-bit bytes (not actually guaranteed by the C standard, but ubiquitous), the range of `unsigned char` is 0..255, and the range of `signed char` is -128..127. ASCII was developed as a 7-bit code using values in the range 0-127, so the same value can be represented by both `char` types.
For the now discovered task of converting a counted hex-string from ascii to unsigned bytes, here's my take:
unsigned int atob(char a){
register int b;
b = a - '0'; // subtract '0' so '0' goes to 0 .. '9' goes to 9
if (b > 9) b = b - ('A' - '0') + 10; // too high! try 'A'..'F'
if (b > 15) b = b - ('a' - 'A); // too high! try 'a'..'f'
return b;
}
void myfunc(const char *in, int n){
int i;
unsigned char *ba;
ba=malloc(n/2);
for (i=0; i < n; i+=2){
ba[i/2] = (atob(in[i]) << 4) | atob(in[i+1]);
}
// ... do something with ba
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is there a printf converter to print in binary format?
Still learning C and I was wondering:
Given a number, is it possible to do something like the following?
char a = 5;
printf("binary representation of a = %b",a);
> 101
Or would i have to write my own method to do the transformation to binary?
There is no direct way (i.e. using printf or another standard library function) to print it. You will have to write your own function.
/* This code has an obvious bug and another non-obvious one :) */
void printbits(unsigned char v) {
for (; v; v >>= 1) putchar('0' + (v & 1));
}
If you're using terminal, you can use control codes to print out bytes in natural order:
void printbits(unsigned char v) {
printf("%*s", (int)ceil(log2(v)) + 1, "");
for (; v; v >>= 1) printf("\x1b[2D%c",'0' + (v & 1));
}
Based on dirkgently's answer, but fixing his two bugs, and always printing a fixed number of digits:
void printbits(unsigned char v) {
int i; // for C89 compatability
for(i = 7; i >= 0; i--) putchar('0' + ((v >> i) & 1));
}
Yes (write your own), something like the following complete function.
#include <stdio.h> /* only needed for the printf() in main(). */
#include <string.h>
/* Create a string of binary digits based on the input value.
Input:
val: value to convert.
buff: buffer to write to must be >= sz+1 chars.
sz: size of buffer.
Returns address of string or NULL if not enough space provided.
*/
static char *binrep (unsigned int val, char *buff, int sz) {
char *pbuff = buff;
/* Must be able to store one character at least. */
if (sz < 1) return NULL;
/* Special case for zero to ensure some output. */
if (val == 0) {
*pbuff++ = '0';
*pbuff = '\0';
return buff;
}
/* Work from the end of the buffer back. */
pbuff += sz;
*pbuff-- = '\0';
/* For each bit (going backwards) store character. */
while (val != 0) {
if (sz-- == 0) return NULL;
*pbuff-- = ((val & 1) == 1) ? '1' : '0';
/* Get next bit. */
val >>= 1;
}
return pbuff+1;
}
Add this main to the end of it to see it in operation:
#define SZ 32
int main(int argc, char *argv[]) {
int i;
int n;
char buff[SZ+1];
/* Process all arguments, outputting their binary. */
for (i = 1; i < argc; i++) {
n = atoi (argv[i]);
printf("[%3d] %9d -> %s (from '%s')\n", i, n,
binrep(n,buff,SZ), argv[i]);
}
return 0;
}
Run it with "progname 0 7 12 52 123" to get:
[ 1] 0 -> 0 (from '0')
[ 2] 7 -> 111 (from '7')
[ 3] 12 -> 1100 (from '12')
[ 4] 52 -> 110100 (from '52')
[ 5] 123 -> 1111011 (from '123')
#include<iostream>
#include<conio.h>
#include<stdlib.h>
using namespace std;
void displayBinary(int n)
{
char bistr[1000];
itoa(n,bistr,2); //2 means binary u can convert n upto base 36
printf("%s",bistr);
}
int main()
{
int n;
cin>>n;
displayBinary(n);
getch();
return 0;
}
Use a lookup table, like:
char *table[16] = {"0000", "0001", .... "1111"};
then print each nibble like this
printf("%s%s", table[a / 0x10], table[a % 0x10]);
Surely you can use just one table, but it will be marginally faster and too big.
There is no direct format specifier for this in the C language. Although I wrote this quick python snippet to help you understand the process step by step to roll your own.
#!/usr/bin/python
dec = input("Enter a decimal number to convert: ")
base = 2
solution = ""
while dec >= base:
solution = str(dec%base) + solution
dec = dec/base
if dec > 0:
solution = str(dec) + solution
print solution
Explained:
dec = input("Enter a decimal number to convert: ") - prompt the user for numerical input (there are multiple ways to do this in C via scanf for example)
base = 2 - specify our base is 2 (binary)
solution = "" - create an empty string in which we will concatenate our solution
while dec >= base: - while our number is bigger than the base entered
solution = str(dec%base) + solution - get the modulus of the number to the base, and add it to the beginning of our string (we must add numbers right to left using division and remainder method). the str() function converts the result of the operation to a string. You cannot concatenate integers with strings in python without a type conversion.
dec = dec/base - divide the decimal number by the base in preperation to take the next modulo
if dec > 0:
solution = str(dec) + solution - if anything is left over, add it to the beginning (this will be 1, if anything)
print solution - print the final number
This code should handle your needs up to 64 bits.
char* pBinFill(long int x,char *so, char fillChar); // version with fill
char* pBin(long int x, char *so); // version without fill
#define width 64
char* pBin(long int x,char *so)
{
char s[width+1];
int i=width;
s[i--]=0x00; // terminate string
do
{ // fill in array from right to left
s[i--]=(x & 1) ? '1':'0'; // determine bit
x>>=1; // shift right 1 bit
} while( x > 0);
i++; // point to last valid character
sprintf(so,"%s",s+i); // stick it in the temp string string
return so;
}
char* pBinFill(long int x,char *so, char fillChar)
{ // fill in array from right to left
char s[width+1];
int i=width;
s[i--]=0x00; // terminate string
do
{
s[i--]=(x & 1) ? '1':'0';
x>>=1; // shift right 1 bit
} while( x > 0);
while(i>=0) s[i--]=fillChar; // fill with fillChar
sprintf(so,"%s",s);
return so;
}
void test()
{
char so[width+1]; // working buffer for pBin
long int val=1;
do
{
printf("%ld =\t\t%#lx =\t\t0b%s\n",val,val,pBinFill(val,so,0));
val*=11; // generate test data
} while (val < 100000000);
}
Output:
00000001 = 0x000001 = 0b00000000000000000000000000000001
00000011 = 0x00000b = 0b00000000000000000000000000001011
00000121 = 0x000079 = 0b00000000000000000000000001111001
00001331 = 0x000533 = 0b00000000000000000000010100110011
00014641 = 0x003931 = 0b00000000000000000011100100110001
00161051 = 0x02751b = 0b00000000000000100111010100011011
01771561 = 0x1b0829 = 0b00000000000110110000100000101001
19487171 = 0x12959c3 = 0b00000001001010010101100111000011
You have to write your own transformation. Only decimal, hex and octal numbers are supported with format specifiers.