integer to string itox function in C - c

I got this from somewhere but i don't kind of understand the meaning behind it.
How does this actually works?
void itox(unsigned int i, char *s)
{
unsigned char n;
s += 4;
*s = '\0';
for (n = 4; n != 0; --n) {
*--s = "0123456789ABCDEF"[i & 0x0F];
i >>= 4;
}
}
Thank you.

It assumes that s is a buffer of length 5 (including the null terminator) and writes the hex representation of i there. The result is the hex representation of i modulo 65536 (for lots of old systems, unsigned int has a range of 0 to 65535).
s += 4;
*s = '\0';
This goes to the end of s and puts a null terminator there.
for (n = 4; n != 0; --n) {
Now we loop backwards through the result string and fill in the appropriate char.
"0123456789ABCDEF"[i & 0x0F];
This selects the correct char. i & 0x0F gets the least significant hex value and by using that as a subscript for array access on "0123456789ABCDEF", the respective char is obtained.
*--s = ...
The char that is obtained is put in the correct place and the pointer is decreased again so the next position can be filled in the next run through the loop.
i >>= 4;
We now shift the number by four bits, removing the four bits we just converted into a hex digit. Now the next four bits will be the least significant hex digit.
Example
let's take the number 58008. In hex it is 0xE298. Mod 16 it is 8, so "0123456789ABCDEF"[8]; gets "8".
Then we shift it four bits, resulting in 3625. Mod 16 that's 9, and we get the "9". After the next shift we get 226, which mod 16 is 2, and one shift later we get 14. "0123456789ABCDEF"[14] is "E".
Assemble those results backwards and you get E298.

The interesting part here is
*--s = "0123456789ABCDEF"[i & 0x0F];
Here "0123456789ABCDEF" is a string literal which is stored in the compiler memory.
We are accessing this literal as an array. So, "0123456789ABCDEF"[0] will be the character '0' and "0123456789ABCDEF"[1] will be '1'
With that information, we can easily analyse the entire code.
s += 4; //Increment pointer s by 4
*s = '\0'; // last value to be '\0' to end the string
for (n = 4; n != 0; --n) {
*--s = "0123456789ABCDEF"[i & 0x0F];
i >>= 4;
}
// say i is 0x231
// For n == 4, i & 0x0F will be 1,
// *--s will point s to the third element in the array, and
// this will be assigned to 1.
// i <<4 will be i/16, so i will be 0x23
// for n == 3,
// *--s will point to second element of array, which will be 3.
// and so on.
Finally what you get is the hexadecimal value of the integer in s

Related

print number of digits of an integer

How to print just for example 3 last digits of a signed integer as hexadecimal number?
int num = -5;
printf("%03X\n", num);
prints FFFFFFFB
I need it to print just FFB
How about:
void printLastThreeHex(int num)
{
size_t len = 0;
char tmp[sizeof(int)*2 + 1]; // two hex chars for each byte + null char
char* str = tmp;
sprintf(tmp, "%03x", num);
len = strlen(tmp);
if (len > 3)
{
str = tmp + len - 3;
}
printf("%s\n", str);
}
I believe the best and clearest way to do this would be a bitmask to hide everything except the last few digits. In your case, this would be printf("%X\n", num & 0xfff);:
0xfffffffb
0x00000fff
-----|||
0x00000ffb
You can adapt this to work with higher bits too. So if you want to extract 0xadb from 0xdeadbeef, it would look like this:
(0xdeadbeef & 0xfff000) >> 12 // gives 0xadb
(0xdeadbeef & 0xfff000) will mask out the bits you want, leaving 0xadb000. To remove these zeroes, right shift by 12 (each hex digit can represent 4 bits, and we need to remove 3 digits, so 4*3 = 12).

Decimal to BCD to ASCII

Perhaps this task is a bit more complicated than what I've written below, but the code that follows is my take on decimal to BCD. The task is to take in a decimal number, convert it to BCD and then to ASCII so that it can be displayed on a microcontroller. As far as I'm aware the code works sufficiently for the basic operation of converting to BCD however I'm stuck when it comes to converting this into ASCII. The overall output is ASCII so that an incremented value can be displayed on an LCD.
My code so far:
int dec2bin(int a){ //Decimal to binary function
int bin;
int i =1;
while (a!=0){
bin+=(a%2)*i;
i*=10;
a/=2;
}
return bin;
}
unsigned int ConverttoBCD(int val){
unsigned int unit = 0;
unsigned int ten = 0;
unsigned int hundred = 0;
hundred = (val/100);
ten = ((val-hundred*100)/10);
unit = (val-(hundred*100+ten*10));
uint8_t ret1 = dec2bin(unit);
uint8_t ret2 = dec2bin((ten)<<4);
uint8_t ret3 = dec2bin((hundred)<<8);
return(ret3+ret2+ret1);
}
The idea to convert to BCD for an ASCII representation of a number is actually the "correct one". Given BCD, you only need to add '0' to each digit for getting the corresponding ASCII value.
But your code has several problems. The most important one is that you try to stuff a value shifted left by 8 bits in an 8bit type. This can never work, those 8 bits will be zero, think about it! Then I absolutely do not understand what your dec2bin() function is supposed to do.
So I'll present you one possible correct solution to your problem. The key idea is to use a char for each individual BCD digit. Of course, a BCD digit only needs 4 bits and a char has at least 8 of them -- but you need char anyways for your ASCII representation and when your BCD digits are already in individual chars, all you have to do is indeed add '0' to each.
While at it: Converting to BCD by dividing and multiplying is a waste of resources. There's a nice algorithm called Double dabble for converting to BCD only using bit shifting and additions. I'm using it in the following example code:
#include <stdio.h>
#include <string.h>
// for determining the number of value bits in an integer type,
// see https://stackoverflow.com/a/4589384/2371524 for this nice trick:
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
// number of bits in unsigned int:
#define UNSIGNEDINT_BITS IMAX_BITS((unsigned)-1)
// convert to ASCII using BCD, return the number of digits:
int toAscii(char *buf, int bufsize, unsigned val)
{
// sanity check, a buffer smaller than one digit is pointless
if (bufsize < 1) return -1;
// initialize output buffer to zero
// if you don't have memset, use a loop here
memset(buf, 0, bufsize);
int scanstart = bufsize - 1;
int i;
// mask for single bits in value, start at most significant bit
unsigned mask = 1U << (UNSIGNEDINT_BITS - 1);
while (mask)
{
// extract single bit
int bit = !!(val & mask);
for (i = scanstart; i < bufsize; ++i)
{
// this is the "double dabble" trick -- in each iteration,
// add 3 to each element that is greater than 4. This will
// generate the correct overflowing bits while shifting for
// BCD
if (buf[i] > 4) buf[i] += 3;
}
// if we have filled the output buffer from the right far enough,
// we have to scan one position earlier in the next iteration
if (buf[scanstart] > 7) --scanstart;
// check for overflow of our buffer:
if (scanstart < 0) return -1;
// now just shift the bits in the BCD digits:
for (i = scanstart; i < bufsize - 1; ++i)
{
buf[i] <<= 1;
buf[i] &= 0xf;
buf[i] |= (buf[i+1] > 7);
}
// shift in the new bit from our value:
buf[bufsize-1] <<= 1;
buf[bufsize-1] &= 0xf;
buf[bufsize-1] |= bit;
// next bit:
mask >>= 1;
}
// find first non-zero digit:
for (i = 0; i < bufsize - 1; ++i) if (buf[i]) break;
int digits = bufsize - i;
// eliminate leading zero digits
// (again, use a loop if you don't have memmove)
// (or, if you're converting to a fixed number of digits and *want*
// the leading zeros, just skip this step entirely, including the
// loop above)
memmove(buf, buf + i, digits);
// convert to ascii:
for (i = 0; i < digits; ++i) buf[i] += '0';
return digits;
}
int main(void)
{
// some simple test code:
char buf[10];
int digits = toAscii(buf, 10, 471142);
for (int i = 0; i < digits; ++i)
{
putchar(buf[i]);
}
puts("");
}
You won't need this IMAX_BITS() "magic macro" if you actually know your target platform and how many bits there are in the integer type you want to convert.

Efficient algorithm for finding a byte in a bit array

Given a bytearray uint8_t data[N] what is an efficient method to find a byte uint8_t search within it even if search is not octet aligned? i.e. the first three bits of search could be in data[i] and the next 5 bits in data[i+1].
My current method involves creating a bool get_bit(const uint8_t* src, struct internal_state* state) function (struct internal_state contains a mask that is bitshifted right, &ed with src and returned, maintaining size_t src_index < size_t src_len) , leftshifting the returned bits into a uint8_t my_register and comparing it with search every time, and using state->src_index and state->src_mask to get the position of the matched byte.
Is there a better method for this?
If you're searching an eight bit pattern within a large array you can implement a sliding window over 16 bit values to check if the searched pattern is part of the two bytes forming that 16 bit value.
To be portable you have to take care of endianness issues which is done by my implementation by building the 16 bit value to search for the pattern manually. The high byte is always the currently iterated byte and the low byte is the following byte. If you do a simple conversion like value = *((unsigned short *)pData) you will run into trouble on x86 processors...
Once value, cmp and mask are setup cmp and mask are shifted. If the pattern was not found within hi high byte the loop continues by checking the next byte as start byte.
Here is my implementation including some debug printouts (the function returns the bit position or -1 if pattern was not found):
int findPattern(unsigned char *data, int size, unsigned char pattern)
{
int result = -1;
unsigned char *pData;
unsigned char *pEnd;
unsigned short value;
unsigned short mask;
unsigned short cmp;
int tmpResult;
if ((data != NULL) && (size > 0))
{
pData = data;
pEnd = data + size;
while ((pData < pEnd) && (result == -1))
{
printf("\n\npData = {%02x, %02x, ...};\n", pData[0], pData[1]);
if ((pData + 1) < pEnd) /* still at least two bytes to check? */
{
tmpResult = (int)(pData - data) * 8; /* calculate bit offset according to current byte */
/* avoid endianness troubles by "manually" building value! */
value = *pData << 8;
pData++;
value += *pData;
/* create a sliding window to check if search patter is within value */
cmp = pattern << 8;
mask = 0xFF00;
while (mask > 0x00FF) /* the low byte is checked within next iteration! */
{
printf("cmp = %04x, mask = %04x, tmpResult = %d\n", cmp, mask, tmpResult);
if ((value & mask) == cmp)
{
result = tmpResult;
break;
}
tmpResult++; /* count bits! */
mask >>= 1;
cmp >>= 1;
}
}
else
{
/* only one chance left if there is only one byte left to check! */
if (*pData == pattern)
{
result = (int)(pData - data) * 8;
}
pData++;
}
}
}
return (result);
}
I don't think you can do much better than this in C:
/*
* Searches for the 8-bit pattern represented by 'needle' in the bit array
* represented by 'haystack'.
*
* Returns the index *in bits* of the first appearance of 'needle', or
* -1 if 'needle' is not found.
*/
int search(uint8_t needle, int num_bytes, uint8_t haystack[num_bytes]) {
if (num_bytes > 0) {
uint16_t window = haystack[0];
if (window == needle) return 0;
for (int i = 1; i < num_bytes; i += 1) {
window = window << 8 + haystack[i];
/* Candidate for unrolling: */
for (int j = 7; j >= 0; j -= 1) {
if ((window >> j) & 0xff == needle) {
return 8 * i - j;
}
}
}
}
return -1;
}
The main idea is to handle the 87.5% of cases that cross the boundary between consecutive bytes by pairing bytes in a wider data type (uint16_t in this case). You could adjust it to use an even wider data type, but I'm not sure that would gain anything.
What you cannot safely or easily do is anything involving casting part or all of your array to a wider integer type via a pointer (i.e. (uint16_t *)&haystack[i]). You cannot be ensured of proper alignment for such a cast, nor of the byte order with which the result might be interpreted.
I don't know if it would be better, but i would use sliding window.
uint counter = 0, feeder = 8;
uint window = data[0];
while (search ^ (window & 0xff)){
window >>= 1;
feeder--;
if (feeder < 8){
counter++;
if (counter >= data.length) {
feeder = 0;
break;
}
window |= data[counter] << feeder;
feeder += 8;
}
}
//Returns index of first bit of first sequence occurrence or -1 if sequence is not found
return (feeder > 0) ? (counter+1)*8-feeder : -1;
Also with some alterations you can use this method to search for arbitrary length (1 to 64-array_element_size_in_bits) bits sequence.
If AVX2 is acceptable (with earlier versions it didn't work out so well, but you can still do something there), you can search in a lot of places at the same time. I couldn't test this on my machine (only compile) so the following is more to give to you an idea of how it could be approached than copy&paste code, so I'll try to explain it rather than just code-dump.
The main idea is to read an uint64_t, shift it right by all values that make sense (0 through 7), then for each of those 8 new uint64_t's, test whether the byte is in there. Small complication: for the uint64_t's shifted by more than 0, the highest position should not be counted since it has zeroes shifted into it that might not be in the actual data. Once this is done, the next uint64_t should be read at an offset of 7 from the current one, otherwise there is a boundary that is not checked across. That's fine though, unaligned loads aren't so bad anymore, especially if they're not wide.
So now for some (untested, and incomplete, see below) code,
__m256i needle = _mm256_set1_epi8(find);
size_t i;
for (i = 0; i < n - 6; i += 7) {
// unaligned load here, but that's OK
uint64_t d = *(uint64_t*)(data + i);
__m256i x = _mm256_set1_epi64x(d);
__m256i low = _mm256_srlv_epi64(x, _mm256_set_epi64x(3, 2, 1, 0));
__m256i high = _mm256_srlv_epi64(x, _mm256_set_epi64x(7, 6, 5, 4));
low = _mm256_cmpeq_epi8(low, needle);
high = _mm256_cmpeq_epi8(high, needle);
// in the qword right-shifted by 0, all positions are valid
// otherwise, the top position corresponds to an incomplete byte
uint32_t lowmask = 0x7f7f7fffu & _mm256_movemask_epi8(low);
uint32_t highmask = 0x7f7f7f7fu & _mm256_movemask_epi8(high);
uint64_t mask = lowmask | ((uint64_t)highmask << 32);
if (mask) {
int bitindex = __builtin_ffsl(mask);
// the bit-index and byte-index are swapped
return 8 * (i + (bitindex & 7)) + (bitindex >> 3);
}
}
The funny "bit-index and byte-index are swapped" thing is because searching within a qword is done byte by byte and the results of those comparisons end up in 8 adjacent bits, while the search for "shifted by 1" ends up in the next 8 bits and so on. So in the resulting masks, the index of the byte that contains the 1 is a bit-offset, but the bit-index within that byte is actually the byte-offset, for example 0x8000 would correspond to finding the byte at the 7th byte of the qword that was right-shifted by 1, so the actual index is 8*7+1.
There is also the issue of the "tail", the part of the data left over when all blocks of 7 bytes have been processed. It can be done much the same way, but now more positions contain bogus bytes. Now n - i bytes are left over, so the mask has to have n - i bits set in the lowest byte, and one fewer for all other bytes (for the same reason as earlier, the other positions have zeroes shifted in). Also, if there is exactly 1 byte "left", it isn't really left because it would have been tested already, but that doesn't really matter. I'll assume the data is sufficiently padded that accessing out of bounds doesn't matter. Here it is, untested:
if (i < n - 1) {
// make n-i-1 bits, then copy them to every byte
uint32_t validh = ((1u << (n - i - 1)) - 1) * 0x01010101;
// the lowest position has an extra valid bit, set lowest zero
uint32_t validl = (validh + 1) | validh;
uint64_t d = *(uint64_t*)(data + i);
__m256i x = _mm256_set1_epi64x(d);
__m256i low = _mm256_srlv_epi64(x, _mm256_set_epi64x(3, 2, 1, 0));
__m256i high = _mm256_srlv_epi64(x, _mm256_set_epi64x(7, 6, 5, 4));
low = _mm256_cmpeq_epi8(low, needle);
high = _mm256_cmpeq_epi8(high, needle);
uint32_t lowmask = validl & _mm256_movemask_epi8(low);
uint32_t highmask = validh & _mm256_movemask_epi8(high);
uint64_t mask = lowmask | ((uint64_t)highmask << 32);
if (mask) {
int bitindex = __builtin_ffsl(mask);
return 8 * (i + (bitindex & 7)) + (bitindex >> 3);
}
}
If you are searching a large amount of memory and can afford an expensive setup, another approach is to use a 64K lookup table. For each possible 16-bit value, the table stores a byte containing the bit shift offset at which the matching octet occurs (+1, so 0 can indicate no match). You can initialize it like this:
uint8_t* g_pLookupTable = malloc(65536);
void initLUT(uint8_t octet)
{
memset(g_pLookupTable, 0, 65536); // zero out
for(int i = 0; i < 65536; i++)
{
for(int j = 7; j >= 0; j--)
{
if(((i >> j) & 255) == octet)
{
g_pLookupTable[i] = j + 1;
break;
}
}
}
}
Note that the case where the value is shifted 8 bits is not included (the reason will be obvious in a minute).
Then you can scan through your array of bytes like this:
int findByteMatch(uint8_t* pArray, uint8_t octet, int length)
{
if(length >= 0)
{
uint16_t index = (uint16_t)pArray[0];
if(index == octet)
return 0;
for(int bit, i = 1; i < length; i++)
{
index = (index << 8) | pArray[i];
if(bit = g_pLookupTable[index])
return (i * 8) - (bit - 1);
}
}
return -1;
}
Further optimization:
Read 32 or however many bits at a time from pArray into a uint32_t and then shift and AND each to get byte one at a time, OR with index and test, before reading another 4.
Pack the LUT into 32K by storing a nybble for each index. This might help it squeeze into the cache on some systems.
It will depend on your memory architecture whether this is faster than an unrolled loop that doesn't use a lookup table.

decimal to hexadecimal unit convertion

I have the next code that converts an decimal unit to an hexadecimal.If i introduce the number 4095 for example, it returns the FFF hexadecimal,but the problem is that i want the number to be printed in a 2 byte format like this(with zeros on the left):
4095 -> 0FFF,
33 -> 0021
i know that there are simpler ways to do this like:
int number = 4095
printf("%04x",number);
but i want to do the conversions and the 2 byte format by myself,but i dont know how to do the zero's on the left procedure.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char Hexadecimal(int rest);
int main()
{
char num_hex,*x,c[2],;
int number = 4095,d,rest;
x = calloc(12,sizeof(char));
for(d = number;d > 0;d/=16)
{
rest = d % 16;
num_hex = Hexadecimal(rest);
sprintf(c,"%c",num_hex);
strcat(x,c);
}
strrev(x);
printf("[%s]\n",x);
return 0;
}
char Hexadecimal(int rest)
{
char letter;
switch(rest)
{
case 10:
letter = 'A';
break;
case 11:
letter = 'B';
break;
case 12:
letter = 'C';
break;
case 13:
letter = 'D';
break;
case 14:
letter = 'E';
break;
case 15:
letter = 'F';
break;
default:
letter = '0' + rest;
}
return letter;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char const Hexadecimal[] = "0123456789ABCDEF";
int main()
{
char num_hex,*x,c[2],;
int number = 4095,d,rest;
x = calloc(12,sizeof(char));
for(d = number;d > 0;d/=16)
{
rest = d % 16;
num_hex = Hexadecimal[rest];
sprintf(c,"%c",num_hex);
strcat(x,c);
}
strrev(x);
printf("[%s]\n",x);
return 0;
}
I think it's easier to think of these problems in terms of binary arithmetic.
Here's an implementation that uses binary math and no standard library functions. It's written in a general way, so you could replace short with int or long and get a similarly correct result (as long as you replace the short type everywhere in the function with your desired type).
char* shortToHex(short value)
{
static char tmp[(sizeof(short)*2)+3] = "0x";
const char* hex = "0123456789ABCDEF";
int i = sizeof(short);
while(i > 0)
{
i--;
char most_significant_nibble = (value >> (i * 8 + 4)) & 0xF;
char least_significant_nibble = (value >> (i * 8)) & 0xF;
tmp[2 + (sizeof(short)-i-1) * 2] = hex[most_significant_nibble];
tmp[2 + (sizeof(short)-i-1) * 2 + 1] = hex[least_significant_nibble];
}
tmp[(sizeof(short)*2)+2] = 0;
return tmp;
}
Let me explain line-by-line so you understand.
static char tmp[(sizeof(short)*2)+3] = "0x";
We need a buffer large enough to hold the amount of nibbles in a short (16 bits == 2 bytes == 4 characters, so two per byte in general) plus a '\0' terminator, plus the "0x" string.
const char* hex = "0123456789ABCDEF";
We need to be able to grab a hexadecimal character based on an array index.
while(i > 0)
{
i--;
...
}
We need a loop counter that counts down from the number of bytes in a short. We're going to loop starting at the most significant byte, to build up the string left-to-right.
char most_significant_nibble = (value >> (i * 8 + 4)) & 0xF;
char least_significant_nibble = (value >> (i * 8)) & 0xF;
tmp[2 + (sizeof(short)-i-1) * 2] = hex[most_significant_nibble];
tmp[2 + (sizeof(short)-i-1) * 2 + 1] = hex[least_significant_nibble];
We're going to shift the bits in the input value to the right, so that the desired bits are in the least-significant nibble of a temporary character. We determine how many bits to shift by multiplying the index (in the case of a 16-bit short, i would start out being 1 since we decremented it, so we'll have 1 * 8 + 4 the first time through the loop, and shift 12 bits to the right, leaving us with the most significant nibble in the short. The second line would shift 8 bits to the right and grab the second nibble. (and so on) The & 0xF portion ensures that whatever 4-bit value we have shifted furthest to the right is the only value in the temporary char.
Then we take those temporary values and set them into the tmp array at the appropriate place. (the math is a little tricky since our index as at the most significant - highest - byte of the value, but we want to place the character at the lowest point in the tmp value.)
tmp[(sizeof(short)*2)+2] = 0;
return tmp;
Lastly, we terminate the tmp string with a '\0' and return it.

unsigned to hex digit

I got a problem that says: Form a character array based on an unsigned int. Array will represent that int in hexadecimal notation. Do this using bitwise operators.
So, my ideas is the following: I create a mask that has 1's for its 4 lowest value bits.
I push the bits of the given int by 4 to the right and use & on that int and mask. I repeat until (int != 0). My question is: when I get individual hex digits (packs of 4 bits), how do I convert them to a char? For example, I get:
x & mask = 1101(2) = 13(10) = D(16)
Is there a function to convert an int to hex representation, or do I have to use brute force with switch statement or whatever else?
I almost forgot, I am doing this in C :)
Here is what I mean:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK 4
int main() {
unsigned int x, y, i, mask;
char a[4];
printf("Enter a positive number: ");
scanf("%u", &x);
for (i = sizeof(usnsigned int), mask = ~(~0 << 4); x; i--, x >>= BLOCK) {
y = x & mask;
a[i] = FICTIVE_NUM_TO_HEX_DIGIT(y);
}
print_array(a);
return EXIT_SUCCESS;
}
You are almost there. The simplest method to convert an integer in the range from 0 to 15 to a hexadecimal digit is to use a lookup table,
char hex_digits[] = "0123456789ABCDEF";
and index into that,
a[i] = hex_digits[y];
in your code.
Remarks:
char a[4];
is probably too small. One hexadecimal digit corresponds to four bits, so with CHAR_BIT == 8, you need up to 2*sizeof(unsigned) chars to represent the number, generally, (CHAR_BIT * sizeof(unsigned int) + 3) / 4. Depending on what print_array does, you may need to 0-terminate a.
for (i = sizeof(usnsigned int), mask = ~(~0 << 4); x; i--, x >>= BLOCK)
initialising i to sizeof(unsigned int) skips the most significant bits, i should be initialised to the last valid index into a (except for possibly the 0-terminator, then the penultimate valid index).
The mask can more simply be defined as mask = 0xF, that has the added benefit of not invoking undefined behaviour, which
mask = ~(~0 << 4)
probably does. 0 is an int, and thus ~0 is one too. On two's complement machines (that is almost everything nowadays), the value is -1, and shifting negative integers left is undefined behaviour.
char buffer[10] = {0};
int h = 17;
sprintf(buffer, "%02X", h);
Try something like this:
char hex_digits[] = "0123456789ABCDEF";
for (i = 0; i < ((sizeof(unsigned int) * CHAR_BIT + 3) / 4); i++) {
digit = (x >> (sizeof(unsigned int) * CHAR_BIT - 4)) & 0x0F;
x = x << 4;
a[i] = hex_digits[digit];
}
Ok, this is where I got:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK 4
void printArray(char*, int);
int main() {
unsigned int x, mask;
int size = sizeof(unsigned int) * 2, i;
char a[size], hexDigits[] = "0123456789ABCDEF";
for (i = 0; i < size; i++)
a[i] = 0;
printf("Enter a positive number: ");
scanf("%u", &x);
for (i = size - 1, mask = ~(~0 << 4); x; i--, x >>= BLOCK) {
a[i] = hexDigits[x & mask];
}
printArray(a, size);
return EXIT_SUCCESS;
}
void printArray(char a[], int n) {
int i;
for (i = 0; i < n; i++)
printf("%c", a[i]);
putchar('\n');
}
I have compiled, it runs and it does the job correctly. I don't know... Should I be worried that this problem was a bit hard for me? At faculty, during exams, we must write our code by hand, on a piece of paper... I don't imagine I would have done this right.
Is there a better (less complicated) way to do this problem? Thank you all for help :)
I would consider the impact of potential padding bits when shifting, as shifting by anything equal to or greater than the number of value bits that exist in an integer type is undefined behaviour.
Perhaps you could terminate the string first using: array[--size] = '\0';, write the smallest nibble (hex digit) using array[--size] = "0123456789ABCDEF"[value & 0x0f], move onto the next nibble using: value >>= 4, and repeat while value > 0. When you're done, return array + size or &array[size] so that the caller knows where the hex sequence begins.

Resources