Thad said:
You are still off by one in your base check, assuming ASCII. If EBCDIC,
it's worse. I am ignoring the superfluous trailing apostrophe for now.
Yes you are right, but I fixed it in my revised code (as you noticed).
There is no superfluous trailing apostrophe; the entire expression is
quoted by `...' (this is the convention used by TeX Info). Maybe `...`
is better, I don't know.
I see you fixed it here.
Assume you start with num=1. The invariant is initially wrong.
No, when num is one rem is zero, so the loop is never entered.
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}
The code will now always generate a leading 0, which I would consider an
error.
I don't know what you mean. Do you have an example?
If you attempt to convert UINT_MAX-1, you will get a divide by 0.
Where would that happen? The denominators are `base' and `power', where
`base' is positive and division by `power' is guarded by
`power > 0'. Try and compile and run the complete program below. On my
32-bit machine i get the (expected) output FFFFFFFE.
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#define BASE_MAX ('9' - '0' + 1 + 'Z' - 'A' + 1)
void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num / base, power = 1, k = 0, digit;
assert((base >= 2) && (base <= BASE_MAX));
while (rem > 0) { /* loop invariant: power * base <= num */
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power; /* digit * power <= rem */
power /= base;
k++;
}
res[k] = '\0';
}
int main(int argc, char *argv[])
{
char buf[32];
get_num_in_base(buf, UINT_MAX - 1, 16);
puts(buf);
return 0;
}
August