I need to convert a (potentially very long) string like char * s = "2f0a3f" into the actual bytes it represents, when decoded from the hex representation. Currently I'm doing this, but it feels clunky and wrong.
size_t hexlength = strlen(s);
size_t binlength = hexlength / 2;
unsigned char * buffer = malloc(binlength);
long i = 0;
char a, b;
for (; i < hexlength; i += 2) {
a = s[i + 0]; b = s[i + 1];
buffer[i / 2] =
((a < '9' ? a - '0' : a - 'a' + 10) << 4) + (b < '9' ? b - '0' : b - 'a' + 10);
}
Two things strike me as ugly about this:
The way I'm dividing by two each time I push into the buffer
The conditional logic to figure out the decimal value of the hex digits
Is there a better way? Preferably not using something I'd have to add a dependency on (since I want to ship this code with minimal cross-platform issues). My bitwise math is awful ;)
NOTE: The data has been pre-validated to all be lowercase and to be a correct string of hex pairs.
/* allocate the buffer */
char * buffer = malloc((strlen(s) / 2) + 1);
char *h = s; /* this will walk through the hex string */
char *b = buffer; /* point inside the buffer */
/* offset into this string is the numeric value */
char xlate[] = "0123456789abcdef";
for ( ; *h; h += 2, ++b) /* go by twos through the hex string */
*b = ((strchr(xlate, *h) - xlate) * 16) /* multiply leading digit by 16 */
+ ((strchr(xlate, *(h+1)) - xlate));
Edited to add
In 80x86 assembly lanugage, the heart of strchr() is basically one instruction - it doesn't loop.
Also: this does no bounds checking, won't work with Unicode console input, and will crash if passed an invalid character.
Also: thanks to those who pointed out some serious typos.
Not that it'd make much difference, but I'd go with a multiplication over a division. Also it's worth splitting out the digit code, as you might want to port it to a platform where a-f are not adjacent in the character set (only joking!)
inline int digittoint(char d) {
return ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10);
}
#define digittoint(d) ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10)
size_t hexlength = strlen(s);
size_t binlength = hexlength / 2;
unsigned char * buffer = malloc(binlength);
long i = 0;
char a, b;
for (; i < binlength; ++i) {
a = s[2 * i + 0]; b = s[2 * i + 1];
buffer[i] = (digittoint(a) << 4) | digittoint(b);
}
I've fixed a bug in your digit-to-int implementation, and replaced the + with bitwise or on the grounds that it better expresses your intent.
You can then experiment to find the best implementation of digittoint - conditional arithmetic as above, strspn, or a lookup table.
Here's a possible branchless implementation that - bonus! - works on uppercase letters:
inline int digittoint(char d) {
return (d & 0x1f) + ((d >> 6) * 0x19) - 0x10;
}
Try something like this:
const unsigned char bin[128] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
int hexlength = strlen(s);
int binlength = (hexlength / 2);
unsigned char * buffer = (unsigned char *) malloc(binlength);
if (buffer)
{
char *hex = s;
unsigned char *buf = buffer;
unsigned char b, c;
int ok = 1;
for (int i = 0; i < hexlength; i += 2)
{
b = bin[*hex++];
c = bin[*hex++];
if ((b == -1) || (c == -1))
{
ok = 0;
break;
)
*buf++ = ((b << 4) | c);
}
if (ok == 1)
{
// use buffer as needed, up to binlength number of bytes...
}
free(buffer);
}
If you need your number (in a string) converted from hex to decimal, you may use atol() with sprintf()
If you need to do it byte-by-byte, you can buffer each byte, and as each buffer is filled, pass it through sprintf as such:
char *hexRep;
char *decRep;
long int decVal;
...
decVal = atol(hexRep);
sprintf(decRep, "%u", decVal);
Both of these are in C's standard library. After you get the string representation of each byte, you could just concatenate them together with strcat().
Here some small improvements to be MISRA complience. The name was confusing.
static inline uint8_t HexcharToInt(char c) {
char result = 16;
if (('0' <= c) && (c <= '9')) {
result = c - '0';
} else if (('a' <= c) && (c <= 'f')) {
result = c + 10 - 'a';
} else if (('A' <= c) && (c <= 'F')) {
result = c + 10 - 'A';
}
return (uint8_t) result;
}
uint8_t *array = NULL;
size_t hexstringToArray(char *hexstring) {
size_t len = (strlen(hexstring) + 1) / 2; // Aufrunden
if (array != NULL) {
free(array);
array = NULL;
}
array = (uint8_t*) malloc(len);
uint8_t *arr = array;
for (size_t i = 0; (i < len) && (len > 0); i++) {
*arr = 0U;
for (uint8_t shift = 8U; (shift > 0U) && (len > 0); ) {
shift -= 4U;
uint8_t curInt = HexcharToInt(*hexstring++);
if (curInt >= 16U) {
len = 0;
} else {
*arr |= ((uint8_t) curInt << shift);
}
}
arr++;
}
return len;
}
I came up with a simpler function that gets the string and copies byte by byte the conversion result to a byte array for a given N size with boundary and integrity check:
int8_t convert_str_to_bytes(uint8_t *byte_array, char* str, size_t n)
{
char *hex_match = "0123456789ABCDEF";
int i, j = 0;
char cbuf[3];
long ibuf;
if (strlen(str) < n) {
printf("ERROR: String is shorter than specified size.\n");
return -1;
}
for (i = 0; i < n; i += 2) {
strncpy(cbuf, &str[i], 2);
if (strspn(cbuf, hex_match) != 2) {
printf("ERROR: String is not a hexadecimal representation. Breaking now...\n");
return -1;
}
ibuf = strtol(cbuf, NULL, 16);
byte_array[j] = (uint8_t)ibuf;
++j;
}
return 0;
}
inline char HexToChar(char c)
{
if ('0' <= c && c <= '9')
{
return c - '0';
}
else if ('a' <= c && c <= 'f')
{
return c + 10 - 'a';
}
else if ('A' <= c && c <= 'F')
{
return c + 10 - 'A';
}
return -1;
}
size_t HexToBinrary( const char* hex, size_t length, char* binrary, size_t binrary_cap )
{
if (length % 2 != 0 || binrary_cap < length / 2)
{
return 0;
}
memset(binrary, 0, binrary_cap);
size_t n = 0;
for (size_t i = 0; i < length; i += 2, ++n)
{
char high = HexToChar(hex[i]);
if (high < 0)
{
return 0;
}
char low = HexToChar(hex[i + 1]);
if (low < 0)
{
return 0;
}
binrary[n] = high << 4 | low;
}
return n;
}
Related
I am attempting to solve the Codewars problem "Sum Strings as Numbers" in which you are given two strings that are numbers and you need to return a string that is the sum of these numbers. My program works for the first few tests but it breaks down when encountering random tests with strings that are hundreds of digits long. If I use the same exact input on and run the program on my own computer, there are no issues. I get this error from code wars:
Test Crashed
Caught unexpected signal: 6
and this in stderr:
free(): invalid pointer
free(): invalid pointer
this is stdout:
START
Initial variables:
llu_strlen a = 236, llu_strlen(b) = 184
llu_strlen(s1) = 236, llu_strlen(s2) = 236
ret = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
s1: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
b: 2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
s2: 00000000000000000000000000000000000000000000000000002750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
entering sum loop:
i = 0, digita = 8, digitb = 4, sumstr=12
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
i = 1, digita = 9, digitb = 5, sumstr=15
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052
i = 2, digita = 7, digitb = 6, sumstr=14
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000452
i = 3, digita = 2, digitb = 6, sumstr=09
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009452
i = 4, digita = 6, digitb = 2, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 5, digita = 3, digitb = 7, sumstr=10
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 6, digita = 9, digitb = 9, sumstr=19
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009089452
i = 7, digita = 9, digitb = 8, sumstr=18
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089089452
i = 8, digita = 3, digitb = 4, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000889089452
i = 9, digita = 7, digitb = 0, sumstr=07
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007889089452
i = 10, digita = 0, digitb = 5, sumstr=05
(continues on like that for a while)
000000000000000000000000000121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 210, digita = 7, digitb = 0, sumstr=07
000000000000000000000000007121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 211, digita = 2, digitb = 0, sumstr=02
000000000000000000000000027121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 212, digita = 8, digitb = 0, sumstr=08
000000000000000000000000827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 213, digita = 4, digitb = 0, sumstr=04
000000000000000000000004827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 214, digita = 6, digitb = 0, sumstr=06
000000000000000000000064827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 215, digita = 9, digitb = 0, sumstr=09
000000000000000000000964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 216, digita = 1, digitb = 0, sumstr=01
000000000000000000001964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 217, digita = 2, digitb = 0, sumstr=02
000000000000000000021964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 218, digita = 7, digitb = 0, sumstr=07
000000000000000000721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 219, digita = 5, digitb = 0, sumstr=05
000000000000000005721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 220, digita = 1, digitb = 0, sumstr=01
000000000000000015721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 221, digita = 9, digitb = 0, sumstr=09
000000000000000915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 222, digita = 6, digitb = 0, sumstr=06
000000000000006915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 223, digita = 4, digitb = 0, sumstr=04
000000000000046915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 224, digita = 9, digitb = 0, sumstr=09
000000000000946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 225, digita = 3, digitb = 0, sumstr=03
000000000003946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 226, digita = 4, digitb = 0, sumstr=04
000000000043946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 227, digita = 4, digitb = 0, sumstr=04
000000000443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 228, digita = 4, digitb = 0, sumstr=04
000000004443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 229, digita
here is the program that I run on code wars which throws an error:
#include <malloc.h>
#include <string.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
and here is the program I run on my computer which finds the result successfully:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
int main(void)
{
char * res;
res = strsum("78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798",
"2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654");
return 0;
}
The error always occurs while the print statement in the sum for loop is printing. The amount of stuff that print statement manages to print out before being cut off changes every time the program is run. This test has random strings of numbers as input, so the input changes each time. The error usually occurs when i approaches maxlen, but i can sometimes be 30-40 less than maxlen.
In your function you allocate ret in this line:
ret = (char *) malloc((maxlen+2) * sizeof(char));
you then return ret at the end of your function, presumably to be freed by the caller.
However within your function you also have these lines:
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
This means that the the ret you are returning no longer has the same pointer value as the one you received from malloc. Then when you call free in the caller the free function doesn't know what the pointer is.
One way to fix this is to find a different way to remove leading zeros, one that doesn't change the value of ret.
These don't have room for the null terminator:
char s1[maxlen], s2[maxlen];
which makes your program write out of bounds and have undefined behavior, so make them:
char s1[maxlen+1], s2[maxlen+1];
And here you change ret, making it impossible for a user to free the malloced memory:
while (*ret == '0' && *(ret+1) != '\0')
ret++;
instead, move the part of the string that you want to keep:
char *tmp = ret;
while (*tmp == '0' && tmp[1] != '\0') tmp++;
memmove(ret, tmp, maxlen-(tmp-ret)+2);
Another detail: You declare ret as static which only makes it unsafe to use the function in a multithreaded program. It does not provide any benefits at all. Just make it:
char *ret;
Another possible improvement would be to not allocate s1 and s2 at all, but to read directly from a and b and to skip leading zeroes before doing the calculation. Example:
#define SWAP(type, x, y) \
do { \
type tmp = x; \
x = y; \
y = tmp; \
} while (0)
char *strsum(const char *a, const char *b) {
while(*a == '0' && a[1] != '\0') ++a; // skip leading zeroes
while(*b == '0' && b[1] != '\0') ++b; // skip leading zeroes
size_t lena = strlen(a);
size_t lenb = strlen(b);
if (lena == 0 || lenb == 0) return NULL;
if (lena < lenb) { // make `a` the longest string
SWAP(const char *, a, b);
SWAP(size_t, lena, lenb);
}
char *ret = malloc(lena + 2); // may add one digit + null terminator
ret[lena + 1] = '\0'; // null terminate the result
int carry = 0;
size_t i = 1;
// loop while both `b` and `a` have digits:
for (; i <= lenb; ++i) {
int sum = carry + (a[lena - i] - '0') + (b[lenb - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// loop while only `a` has digits:
for (; i <= lena; ++i) {
int sum = carry + (a[lena - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// if no carry, move everything one step to the left:
if (carry == 0) memmove(ret, ret + 1, lena + 2 - 1);
else ret[0] = carry + '0'; // carry goes to the first position
return ret;
}
Demo
I know it's a simple question, but I am completely lost.
I have in input a string:
input: 220209
I want:
output: uint8_t myarr[8]={0x22,0x02,0x09,0x00, 0x00, 0x00,0x00,0x00}
So myarr has always a dimension of 8, and if I have a lower input string I have to complete with 0x00. Can someone give me any idea?
Sorry for bothering you, any help will be appreciated.
Regards
Using strtol() to convert 2 characters at a time, explicitly using base 16 makes it easy:
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
// Assume s has an even number of hexdigit chars (at most 16) followed by a nul
void convert(const char *s, uint8_t out[static 8]) {
int i = 0;
// Handle 2 chars at a time
while (*s) {
char byte[3] = { *s, *(s + 1), 0 };
out[i++] = strtol(byte, NULL, 16);
s += 2;
}
// Fill the rest of the array with nuls
for (; i < 8; i += 1) {
out[i] = 0;
}
}
int main(void)
{
const char *input = "220209";
uint8_t myarr[8];
convert(input, myarr);
// Pretty-print the array using hex values
fputs("uint8_t myarr[8] = { ", stdout);
for (int i = 0; i < 8; i += 1) {
printf("0x%02" PRIx8, myarr[i]);
if (i < 7) {
fputs(", ", stdout);
}
}
puts(" };");
return 0;
}
Another option is to use sscanf() to parse two characters at a time:
void convert(const char *s, uint8_t out[8])
{
memset(out, 0, 8);
while (sscanf(s, "%2"SCNx8, out++) == 1) {
s += 2;
}
}
The first line sets the 8 bytes to 0 by taking advantage of 64 bits arithmetics. Then we scan two characters from string s, reading an integer of type uint8_t from hexdecimal ASCII representation. If the read was successful, we move to the next two characters.
It looks like a code golf submission, but it's nice, because nothing gets copied.
Another version could be:
void convert(const char *s, uint8_t out[8])
{
static char tbl[] = {
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
};
memset(out, 0, 8);
while (*s) {
*out++ = tbl[s[0]] * 16 + tbl[s[1]];
s += 2;
}
}
Hope it can work for you
memset(myarr, 0, 8);
int szLen = strlen(szInput);
for(int i = 0; i < szLen / 2; i++) {
uint8_t high = toupper(szInput[i*2]);
uint8_t low = toupper(szInput[i*2 + 1]);
if(high >= '0' && high <= '9')
high = high - '0';
if(low >= '0' && low <= '9')
low = low - '0';
if(high >= 'A' && high <= 'F')
high = high - 'A' + 10;
if(low >= 'A' && low <= 'F')
low = low - 'A' + 10;
myarr[i] = (high << 4) | low; // bit operation is faster than arithmetic
}
itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, "%d", num)?
EDIT: Sorry, I should have remembered that this machine is decidedly non-standard, having plugged in various non-standard libc implementations for academic purposes ;-)
As itoa() is indeed non-standard, as mentioned by several helpful commenters, it is best to use sprintf(target_string,"%d",source_int) or (better yet, because it's safe from buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). I know it's not quite as concise or cool as itoa(), but at least you can Write Once, Run Everywhere (tm) ;-)
Here's the old (edited) answer
You are correct in stating that the default gcc libc does not include itoa(), like several other platforms, due to it not technically being a part of the standard. See here for a little more info. Note that you have to
#include <stdlib.h>
Of course you already know this, because you wanted to use itoa() on Linux after presumably using it on another platform, but... the code (stolen from the link above) would look like:
Example
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Output:
Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110
itoa is not a standard C function. You can implement your own. It appeared in the first edition of Kernighan and Ritchie's The C Programming Language, on page 60. The second edition of The C Programming Language ("K&R2") contains the following implementation of itoa, on page 64. The book notes several issues with this implementation, including the fact that it does not correctly handle the most negative number
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
The function reverse used above is implemented two pages earlier:
#include <string.h>
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
If you are calling it a lot, the advice of "just use snprintf" can be annoying. So here's what you probably want:
const char *my_itoa_buf(char *buf, size_t len, int num)
{
static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */
if (!buf)
{
buf = loc_buf;
len = sizeof(loc_buf);
}
if (snprintf(buf, len, "%d", num) == -1)
return ""; /* or whatever */
return buf;
}
const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }
Edit: I just found out about std::to_string which is identical in operation to my own function below. It was introduced in C++11 and is available in recent versions of gcc, at least as early as 4.5 if you enable the c++0x extensions.
Not only is itoa missing from gcc, it's not the handiest function to use since you need to feed it a buffer. I needed something that could be used in an expression so I came up with this:
std::string itos(int n)
{
const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
char buffer[max_size] = {0};
sprintf(buffer, "%d", n);
return std::string(buffer);
}
Ordinarily it would be safer to use snprintf instead of sprintf but the buffer is carefully sized to be immune to overrun.
See an example: http://ideone.com/mKmZVE
As Matt J wrote, there is itoa, but it's not standard. Your code will be more portable if you use snprintf.
Following function allocates just enough memory to keep string representation of the given number and then writes the string representation into this area using standard sprintf method.
char *itoa(long n)
{
int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
if (n<0) len++; // room for negative sign '-'
char *buf = calloc(sizeof(char), len+1); // +1 for null
snprintf(buf, len+1, "%ld", n);
return buf;
}
Don't forget to free up allocated memory when out of need:
char *num_str = itoa(123456789L);
// ...
free(num_str);
N.B. As snprintf copies n-1 bytes, we have to call snprintf(buf, len+1, "%ld", n) (not just snprintf(buf, len, "%ld", n))
Where is the itoa function in Linux?
There is no such function in Linux. I use this code instead.
/*
=============
itoa
Convert integer to string
PARAMS:
- value A 64-bit number to convert
- str Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
boolean sign = false;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = true;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
Reading the code of guys who do it for a living will get you a LONG WAY.
Check out how guys from MySQL did it. The source is VERY WELL COMMENTED and will teach you much more than hacked up solutions found all over the place.
MySQL's implementation of int2str
I provide the mentioned implementation here; the link is here for reference and should be used to read the full implementation.
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
i tried my own implementation of itoa(), it seem's work in binary, octal, decimal and hex
#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)
static char * my_itoa ( int value, char * str, int base )
{
int i,n =2,tmp;
char buf[BIN_LEN+1];
switch(base)
{
case 16:
for(i = 0;i<HEX_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%x" ,value);
break;
case 10:
for(i = 0;i<INT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%d" ,value);
break;
case 8:
for(i = 0;i<OCT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%o" ,value);
break;
case 2:
for(i = 0,tmp = value;i<BIN_LEN;++i)
{
if(tmp/base>0)
{
n++;
}
tmp/=base;
}
for(i = 1 ,tmp = value; i<n;++i)
{
if(tmp%2 != 0)
{
buf[n-i-1] ='1';
}
else
{
buf[n-i-1] ='0';
}
tmp/=base;
}
buf[n-1] = '\0';
strcpy(str,buf);
break;
default:
return NULL;
}
return str;
}
direct copy to buffer : 64 bit integer itoa hex :
char* itoah(long num, char* s, int len)
{
long n, m = 16;
int i = 16+2;
int shift = 'a'- ('9'+1);
if(!s || len < 1)
return 0;
n = num < 0 ? -1 : 1;
n = n * num;
len = len > i ? i : len;
i = len < i ? len : i;
s[i-1] = 0;
i--;
if(!num)
{
if(len < 2)
return &s[i];
s[i-1]='0';
return &s[i-1];
}
while(i && n)
{
s[i-1] = n % m + '0';
if (s[i-1] > '9')
s[i-1] += shift ;
n = n/m;
i--;
}
if(num < 0)
{
if(i)
{
s[i-1] = '-';
i--;
}
}
return &s[i];
}
note: change long to long long for 32 bit machine. long to int in case for 32 bit integer. m is the radix. When decreasing radix, increase number of characters (variable i). When increasing radix, decrease number of characters (better). In case of unsigned data type, i just becomes 16 + 1.
Here is a much improved version of Archana's solution. It works for any radix 1-16, and numbers <= 0, and it shouldn't clobber memory.
static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";
static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
for (int index = 0; index < (len / 2); index++)
{
char ch = buffer[index];
buffer[index] = buffer[len - index - 1];
buffer[len - index - 1] = ch;
}
}
static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
if (radix == 10)
{
if (len < (bufferSize - 1))
{
buffer[len++] = '-';
buffer[len] = '\0';
}
}
else
{
int twosCompIndex = 0;
for (int index = 0; index < len; index++)
{
if ((buffer[index] >= '0') && (buffer[index] <= '9'))
{
twosCompIndex = buffer[index] - '0';
}
else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
{
twosCompIndex = buffer[index] - 'A' + 10;
}
else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
{
twosCompIndex = buffer[index] - 'a' + 10;
}
twosCompIndex += (16 - radix);
buffer[index] = _twosComp[twosCompIndex];
}
if (len < (bufferSize - 1))
{
buffer[len++] = _numberSystem[radix - 1];
buffer[len] = 0;
}
}
return len;
}
static int twosNegation(const int x, const int radix)
{
int n = x;
if (x < 0)
{
if (radix == 10)
{
n = -x;
}
else
{
n = ~x;
}
}
return n;
}
static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
int strlen = 0;
int n = twosNegation(x, radix);
int nuberSystemIndex = 0;
if (radix <= 16)
{
do
{
if (strlen < (bufferSize - 1))
{
nuberSystemIndex = (n % radix);
buffer[strlen++] = _numberSystem[nuberSystemIndex];
buffer[strlen] = '\0';
n = n / radix;
}
else
{
break;
}
} while (n != 0);
if (x < 0)
{
strlen = negateBuffer(buffer, bufferSize, strlen, radix);
}
safestrrev(buffer, bufferSize, strlen);
return buffer;
}
return NULL;
}
Where is the itoa function in Linux?
As itoa() is not standard in C, various versions with various function signatures exists.
char *itoa(int value, char *str, int base); is common in *nix.
Should it be missing from Linux or if code does not want to limit portability, code could make it own.
Below is a version that does not have trouble with INT_MIN and handles problem buffers: NULL or an insufficient buffer returns NULL.
#include <stdlib.h>
#include <limits.h>
#include <string.h>
// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object) ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)
char *itoa_x(int number, char *dest, size_t dest_size) {
if (dest == NULL) {
return NULL;
}
char buf[SIGNED_PRINT_SIZE(number)];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = (char) ('0' - neg_num % 10);
neg_num /= 10;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Below is a C99 or later version that handles any base [2...36]
char *itoa_x(int number, char *dest, size_t dest_size, int base) {
if (dest == NULL || base < 2 || base > 36) {
return NULL;
}
char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to avoid UB of `abs(INT_MIN)`
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
neg_num /= base;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
For a C89 and onward compliant code, replace inner loop with
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
glibc internal implementation
glibc 2.28 has an internal implementation:
stdio-common/_itoa.c
sysdeps/generic/_itoa.h
which is used in several places internally, but I could not find if it can be exposed or how.
At least that should be a robust implementation if you are willing to extract it.
This question asks how to roll your own: How to convert an int to string in C?
I would prefer this: https://github.com/wsq003/itoa_for_linux
It should be the fastest itoa() ever. We use itoa() instead of sprintf() for performance reason, so a fastest itoa() with limited feature is reasonable and worthwhile.
If you just want to print them:
void binary(unsigned int n)
{
for(int shift=sizeof(int)*8-1;shift>=0;shift--)
{
if (n >> shift & 1)
printf("1");
else
printf("0");
}
printf("\n");
}
The replacement with snprintf is NOT complete!
It covers only bases: 2, 8, 10, 16, whereas itoa works for bases between 2 and 36.
Since I was searching a replacement for base 32, I guess I'll have to code my own!
I have used _itoa(...) on RedHat 6 and GCC compiler. It works.
You can use this program instead of sprintf.
void itochar(int x, char *buffer, int radix);
int main()
{
char buffer[10];
itochar(725, buffer, 10);
printf ("\n %s \n", buffer);
return 0;
}
void itochar(int x, char *buffer, int radix)
{
int i = 0 , n,s;
n = s;
while (n > 0)
{
s = n%radix;
n = n/radix;
buffer[i++] = '0' + s;
}
buffer[i] = '\0';
strrev(buffer);
}
i took the code from the links below to encrypt and decrypt a text
but i get segmentation fault when trying to run this any ideas??
http://etutorials.org/Programming/secure+programming/Chapter+4.+Symmetric+Cryptography+Fundamentals/4.5+Performing+Base64+Encoding/
http://etutorials.org/Programming/secure+programming/Chapter+4.+Symmetric+Cryptography+Fundamentals/4.6+Performing+Base64+Decoding/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static char b64revtb[256] = {
-3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*0-15*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16-31*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /*32-47*/
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /*48-63*/
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /*64-79*/
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /*80-95*/
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /*96-111*/
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /*112-127*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128-143*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*144-159*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*160-175*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*176-191*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*192-207*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*208-223*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*224-239*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /*240-255*/
};
unsigned char *spc_base64_encode( unsigned char *input
, size_t len
, int wrap ) ;
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict,
int *err);
static unsigned int raw_base64_decode(unsigned char *in, unsigned char *out,
int strict, int *err);
unsigned char *tmbuf = NULL;
static char tmpbuffer[] ={0};
int main(void)
{
memset( tmpbuffer, NULL, sizeof( tmpbuffer ) );
sprintf( tmpbuffer, "%s:%s" , "username", "password" );
tmbuf = spc_base64_encode( (unsigned char *)tmpbuffer , strlen( tmpbuffer ), 0 );
printf(" The text %s has been encrytped to %s \n", tmpbuffer, tmbuf );
unsigned char *decrypt = NULL;
int strict;
int *err;
decrypt = spc_base64_decode( tmbuf , strlen( tmbuf ), 0, err );
printf(" The text %s has been decrytped to %s \n", tmbuf , decrypt);
}
static char b64table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Accepts a binary buffer with an associated size.
* Returns a base64 encoded, NULL-terminated string.
*/
unsigned char *spc_base64_encode(unsigned char *input, size_t len, int wrap) {
unsigned char *output, *p;
size_t i = 0, mod = len % 3, toalloc;
toalloc = (len / 3) * 4 + (3 - mod) % 3 + 1;
if (wrap) {
toalloc += len / 57;
if (len % 57) toalloc++;
}
p = output = (unsigned char *)malloc(((len / 3) + (mod ? 1 : 0)) * 4 + 1);
if (!p) return 0;
while (i < len - mod) {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
*p++ = b64table[((input[i] << 2) | (input[i + 1] >> 6)) & 0x3f];
*p++ = b64table[input[i + 1] & 0x3f];
i += 2;
if (wrap && !(i % 57)) *p++ = '\n';
}
if (!mod) {
if (wrap && i % 57) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
if (mod = = 1) {
*p++ = '=';
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[(input[i] << 2) & 0x3f];
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
}
}
}
static unsigned int raw_base64_decode(unsigned char *in, unsigned char *out,
int strict, int *err) {
unsigned int result = 0, x;
unsigned char buf[3], *p = in, pad = 0;
*err = 0;
while (!pad) {
switch ((x = b64revtb[*p++])) {
case -3: /* NULL TERMINATOR */
if (((p - 1) - in) % 4) *err = 1;
return result;
case -2: /* PADDING CHARACTER. INVALID HERE */
if (((p - 1) - in) % 4 < 2) {
*err = 1;
return result;
}
else if (((p - 1) - in) % 4 == 2)
{
/* Make sure there's appropriate padding */
if (*p != '=') {
*err = 1;
return result;
}
buf[2] = 0;
pad = 2;
result++;
break;
} else {
pad = 1;
result += 2;
break;
}
case -1:
if (strict) {
*err = 2;
return result;
}
break;
default:
switch (((p - 1) - in) % 4) {
case 0:
buf[0] = x << 2;
break;
case 1:
buf[0] |= (x >> 4);
buf[1] = x << 4;
break;
case 2:
buf[1] |= (x >> 2);
buf[2] = x << 6;
break;
case 3:
buf[2] |= x;
result += 3;
for (x = 0; x < 3 - pad; x++) *out++ = buf[x];
break;
}
break;
}
}
for (x = 0; x < 3 - pad; x++) *out++ = buf[x];
return result;
}
/* If err is non-zero on exit, then there was an incorrect padding error. We
* allocate enough space for all circumstances, but when there is padding, or
* there are characters outside the character set in the string (which we are
* supposed to ignore), then we end up allocating too much space. You can
* realloc() to the correct length if you wish.
*/
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict,
int *err) {
unsigned char *outbuf;
outbuf = (unsigned char *)malloc(3 * (strlen(buf) / 4 + 1));
if (!outbuf) {
*err = -3;
*len = 0;
return 0;
}
*len = raw_base64_decode(buf, outbuf, strict, err);
if (*err) {
free(outbuf);
*len = 0;
outbuf = 0;
}
return outbuf;
}
tmpbuffer is not properly defined/allocated.
static char tmpbuffer[] ={0};
produces a buffer which can contain only 1 character, but
sprintf( tmpbuffer, "%s:%s" , "username", "password" );
attempts to write many more bytes...
Further inspection of the code shows other errors...
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict, int *err)
Note how the 2nd arg is a pointer to size_t, yet it is passed...
decrypt = spc_base64_decode( tmbuf , strlen( tmbuf ), 0, err );
an immediate value... Oops...
itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, "%d", num)?
EDIT: Sorry, I should have remembered that this machine is decidedly non-standard, having plugged in various non-standard libc implementations for academic purposes ;-)
As itoa() is indeed non-standard, as mentioned by several helpful commenters, it is best to use sprintf(target_string,"%d",source_int) or (better yet, because it's safe from buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). I know it's not quite as concise or cool as itoa(), but at least you can Write Once, Run Everywhere (tm) ;-)
Here's the old (edited) answer
You are correct in stating that the default gcc libc does not include itoa(), like several other platforms, due to it not technically being a part of the standard. See here for a little more info. Note that you have to
#include <stdlib.h>
Of course you already know this, because you wanted to use itoa() on Linux after presumably using it on another platform, but... the code (stolen from the link above) would look like:
Example
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Output:
Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110
itoa is not a standard C function. You can implement your own. It appeared in the first edition of Kernighan and Ritchie's The C Programming Language, on page 60. The second edition of The C Programming Language ("K&R2") contains the following implementation of itoa, on page 64. The book notes several issues with this implementation, including the fact that it does not correctly handle the most negative number
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
The function reverse used above is implemented two pages earlier:
#include <string.h>
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
If you are calling it a lot, the advice of "just use snprintf" can be annoying. So here's what you probably want:
const char *my_itoa_buf(char *buf, size_t len, int num)
{
static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */
if (!buf)
{
buf = loc_buf;
len = sizeof(loc_buf);
}
if (snprintf(buf, len, "%d", num) == -1)
return ""; /* or whatever */
return buf;
}
const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }
Edit: I just found out about std::to_string which is identical in operation to my own function below. It was introduced in C++11 and is available in recent versions of gcc, at least as early as 4.5 if you enable the c++0x extensions.
Not only is itoa missing from gcc, it's not the handiest function to use since you need to feed it a buffer. I needed something that could be used in an expression so I came up with this:
std::string itos(int n)
{
const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
char buffer[max_size] = {0};
sprintf(buffer, "%d", n);
return std::string(buffer);
}
Ordinarily it would be safer to use snprintf instead of sprintf but the buffer is carefully sized to be immune to overrun.
See an example: http://ideone.com/mKmZVE
As Matt J wrote, there is itoa, but it's not standard. Your code will be more portable if you use snprintf.
Following function allocates just enough memory to keep string representation of the given number and then writes the string representation into this area using standard sprintf method.
char *itoa(long n)
{
int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
if (n<0) len++; // room for negative sign '-'
char *buf = calloc(sizeof(char), len+1); // +1 for null
snprintf(buf, len+1, "%ld", n);
return buf;
}
Don't forget to free up allocated memory when out of need:
char *num_str = itoa(123456789L);
// ...
free(num_str);
N.B. As snprintf copies n-1 bytes, we have to call snprintf(buf, len+1, "%ld", n) (not just snprintf(buf, len, "%ld", n))
Where is the itoa function in Linux?
There is no such function in Linux. I use this code instead.
/*
=============
itoa
Convert integer to string
PARAMS:
- value A 64-bit number to convert
- str Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
boolean sign = false;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = true;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
Reading the code of guys who do it for a living will get you a LONG WAY.
Check out how guys from MySQL did it. The source is VERY WELL COMMENTED and will teach you much more than hacked up solutions found all over the place.
MySQL's implementation of int2str
I provide the mentioned implementation here; the link is here for reference and should be used to read the full implementation.
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
i tried my own implementation of itoa(), it seem's work in binary, octal, decimal and hex
#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)
static char * my_itoa ( int value, char * str, int base )
{
int i,n =2,tmp;
char buf[BIN_LEN+1];
switch(base)
{
case 16:
for(i = 0;i<HEX_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%x" ,value);
break;
case 10:
for(i = 0;i<INT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%d" ,value);
break;
case 8:
for(i = 0;i<OCT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%o" ,value);
break;
case 2:
for(i = 0,tmp = value;i<BIN_LEN;++i)
{
if(tmp/base>0)
{
n++;
}
tmp/=base;
}
for(i = 1 ,tmp = value; i<n;++i)
{
if(tmp%2 != 0)
{
buf[n-i-1] ='1';
}
else
{
buf[n-i-1] ='0';
}
tmp/=base;
}
buf[n-1] = '\0';
strcpy(str,buf);
break;
default:
return NULL;
}
return str;
}
direct copy to buffer : 64 bit integer itoa hex :
char* itoah(long num, char* s, int len)
{
long n, m = 16;
int i = 16+2;
int shift = 'a'- ('9'+1);
if(!s || len < 1)
return 0;
n = num < 0 ? -1 : 1;
n = n * num;
len = len > i ? i : len;
i = len < i ? len : i;
s[i-1] = 0;
i--;
if(!num)
{
if(len < 2)
return &s[i];
s[i-1]='0';
return &s[i-1];
}
while(i && n)
{
s[i-1] = n % m + '0';
if (s[i-1] > '9')
s[i-1] += shift ;
n = n/m;
i--;
}
if(num < 0)
{
if(i)
{
s[i-1] = '-';
i--;
}
}
return &s[i];
}
note: change long to long long for 32 bit machine. long to int in case for 32 bit integer. m is the radix. When decreasing radix, increase number of characters (variable i). When increasing radix, decrease number of characters (better). In case of unsigned data type, i just becomes 16 + 1.
Here is a much improved version of Archana's solution. It works for any radix 1-16, and numbers <= 0, and it shouldn't clobber memory.
static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";
static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
for (int index = 0; index < (len / 2); index++)
{
char ch = buffer[index];
buffer[index] = buffer[len - index - 1];
buffer[len - index - 1] = ch;
}
}
static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
if (radix == 10)
{
if (len < (bufferSize - 1))
{
buffer[len++] = '-';
buffer[len] = '\0';
}
}
else
{
int twosCompIndex = 0;
for (int index = 0; index < len; index++)
{
if ((buffer[index] >= '0') && (buffer[index] <= '9'))
{
twosCompIndex = buffer[index] - '0';
}
else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
{
twosCompIndex = buffer[index] - 'A' + 10;
}
else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
{
twosCompIndex = buffer[index] - 'a' + 10;
}
twosCompIndex += (16 - radix);
buffer[index] = _twosComp[twosCompIndex];
}
if (len < (bufferSize - 1))
{
buffer[len++] = _numberSystem[radix - 1];
buffer[len] = 0;
}
}
return len;
}
static int twosNegation(const int x, const int radix)
{
int n = x;
if (x < 0)
{
if (radix == 10)
{
n = -x;
}
else
{
n = ~x;
}
}
return n;
}
static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
int strlen = 0;
int n = twosNegation(x, radix);
int nuberSystemIndex = 0;
if (radix <= 16)
{
do
{
if (strlen < (bufferSize - 1))
{
nuberSystemIndex = (n % radix);
buffer[strlen++] = _numberSystem[nuberSystemIndex];
buffer[strlen] = '\0';
n = n / radix;
}
else
{
break;
}
} while (n != 0);
if (x < 0)
{
strlen = negateBuffer(buffer, bufferSize, strlen, radix);
}
safestrrev(buffer, bufferSize, strlen);
return buffer;
}
return NULL;
}
Where is the itoa function in Linux?
As itoa() is not standard in C, various versions with various function signatures exists.
char *itoa(int value, char *str, int base); is common in *nix.
Should it be missing from Linux or if code does not want to limit portability, code could make it own.
Below is a version that does not have trouble with INT_MIN and handles problem buffers: NULL or an insufficient buffer returns NULL.
#include <stdlib.h>
#include <limits.h>
#include <string.h>
// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object) ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)
char *itoa_x(int number, char *dest, size_t dest_size) {
if (dest == NULL) {
return NULL;
}
char buf[SIGNED_PRINT_SIZE(number)];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = (char) ('0' - neg_num % 10);
neg_num /= 10;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Below is a C99 or later version that handles any base [2...36]
char *itoa_x(int number, char *dest, size_t dest_size, int base) {
if (dest == NULL || base < 2 || base > 36) {
return NULL;
}
char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to avoid UB of `abs(INT_MIN)`
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
neg_num /= base;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
For a C89 and onward compliant code, replace inner loop with
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
glibc internal implementation
glibc 2.28 has an internal implementation:
stdio-common/_itoa.c
sysdeps/generic/_itoa.h
which is used in several places internally, but I could not find if it can be exposed or how.
At least that should be a robust implementation if you are willing to extract it.
This question asks how to roll your own: How to convert an int to string in C?
I would prefer this: https://github.com/wsq003/itoa_for_linux
It should be the fastest itoa() ever. We use itoa() instead of sprintf() for performance reason, so a fastest itoa() with limited feature is reasonable and worthwhile.
If you just want to print them:
void binary(unsigned int n)
{
for(int shift=sizeof(int)*8-1;shift>=0;shift--)
{
if (n >> shift & 1)
printf("1");
else
printf("0");
}
printf("\n");
}
The replacement with snprintf is NOT complete!
It covers only bases: 2, 8, 10, 16, whereas itoa works for bases between 2 and 36.
Since I was searching a replacement for base 32, I guess I'll have to code my own!
I have used _itoa(...) on RedHat 6 and GCC compiler. It works.
You can use this program instead of sprintf.
void itochar(int x, char *buffer, int radix);
int main()
{
char buffer[10];
itochar(725, buffer, 10);
printf ("\n %s \n", buffer);
return 0;
}
void itochar(int x, char *buffer, int radix)
{
int i = 0 , n,s;
n = s;
while (n > 0)
{
s = n%radix;
n = n/radix;
buffer[i++] = '0' + s;
}
buffer[i] = '\0';
strrev(buffer);
}