Reputation: 31
I am trying to implement the following (without sprintf
or formatting):
void integer_to_string(unsigned int a, char *string)
{
char arr[16] = "0123456789abcdef";
char *p = (char *)&a;
unsigned int i;
for (i = 0; i < 4; i++) {
unsigned char lo = p[i] & 0xf;
unsigned char hi = p[i] >> 4;
string[i * 2] = arr[hi];
string[i * 2 + 1] = arr[lo];
}
string[2 * i] = '\0';
}
This program is converting from an integer a
and converting a
into hexadecimal and saving the rest as a string. So, it is supposed to return an int like 10
to "0000000a"
but instead is giving me a value of "0a000000"
instead. What am I doing wrong? How do I move the 0a
to the end instead of the beginning.
Upvotes: 3
Views: 1798
Reputation: 1
Maybe not the best, but certainly a fast one...
This function returns a char*
containing the HEX version of any unsigned integer of 32 bits or fewer that is passed to it...
example: u32tohex(284598256);
will return "0x10F69FF0"
as char*
the return char[] must be declared outside the function, because returning the pointer of a local variable will not work!
char dex[11] = "0x00000000";
const char* u32tohex(uint32_t ul)
{
const char HexC[17]="0123456789ABCDEF";
for (uint8_t xh=9; xh>1; xh--)
{
dex[xh]=HexC[ul&0xf];
ul>>=4;
}
return &dex;
}
or the same without the prefix "0x"
...
example: u32tohex(121345243);
will return "073B94DB"
as char*
char dex[9] = "00000000";
const char* u32tohex(uint32_t ul)
{
const char HexC[17]="0123456789ABCDEF";
for (uint8_t xh=0; xh<8; xh++)
{
dex[7-xh]=HexC[ul&0xf];
ul>>=4;
}
return &dex;
}
Probably, a bit difficult to understand at first glance, but the less manipulation done to variables, will always yield a fast function... the Unsigned integer of 32 bit passed to the function is stored in ul, the loop starts by the end of the char[] result, and going backward... because I only bitwise AND ul with the 0xf, to get the least significant nibble, in one shot and set the final character form the HexC[]... and right shift the ul of 4 bits, getting rid of the last nibble, and replacing it by the next one... only 8 iterations, and the job is done... It may seem useless to have a fast function for this purpose, for a few conventions, but if you use it in a disassembler, to display the address at every line on the screen, as well as the data from those addresses, the speed of the refresh, while scrolling the screen will be very responsive, compared to many other solutions...
Upvotes: 0
Reputation: 144550
The output is incorrect because your system uses little endian ordering for the bytes that form the int
values in memory. This is a very common case nowadays. Casting the address of a
as a char *
leads to non portable code.
You should instead write portable code that does not depend on the internal representation of integers this way:
// convert an unsigned int to its hexadecimal representation in a string
// assuming str points to an array of at least 9 bytes
// assuming unsigned int type has 32 bits
// returns its second argument for ease of use in chained expressions
char *integer_to_string(unsigned int a, char *str) {
str[8] = '\0';
for (int i = 0; i < 8; i++) {
str[7 - i] = "0123456789abcdef"[a & 0xF];
a = a >> 4;
}
return str;
}
Upvotes: 0
Reputation: 153338
Accessing the correct significant bytes via char *p = (char *)&a;
is endian dependent and in OP's case, the wrong order.
Get the order right and avoid endian-ness issues by using math, not casts:
for (i = 0; i < 8; i++) {
unsigned char ch = (a >> ((32-4) - i*4)) & 0xF;
string[i] = arr[ch];
}
string[i] = '\0';
Simplification exist.
Upvotes: 4