exc/k&r/02-types-operators-and-exp/02-bitwise.c

90 lines
2.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "02-bitwise.h"
#define BASES X("0b", 2) X("0", 8) X("", 10) X("0x", 16)
#define X(p, b) int int_of_base_##b(unsigned *x, char *s);
BASES
#undef X
/* printd_base: prints x in base b */
void printd_base(int b, unsigned x)
{
if (!x) {
putchar('0');
return;
}
switch (b) {
#define X(p, b) case b : printf("%s", p); break;
BASES
#undef X
}
unsigned m;
for (m = 1; m * b <= x && m * b > 0; m *= b)
;
char d;
while (m > 0) {
if ((d = x / m) > 9)
putchar(d - 10 + 'a');
else
putchar(d + '0');
x %= m;
m /= b;
}
}
/* int_of_string: converts string s to int, writes result to *x and returns base
* of the ints string representation or 0 if s is invalid */
int int_of_string(unsigned *x, char *s)
{
switch (*s) {
case '0' :
switch (*(s+1)) {
case 'b' :
return int_of_base_2(x, s+2);
case 'x' :
return int_of_base_16(x, s+2);
default :
return int_of_base_8(x, s+1);
}
default :
return int_of_base_10(x, s);
}
return 0;
}
/* int_of_base_b: for base b, convert number string in base b to int and
* write it to *x. return b or 0 if invalid */
#define MAKE_INT_OF_BASE(b) \
int int_of_base_##b(unsigned *x, char *s) \
{ \
char d; \
unsigned px = 0; \
*x = 0; \
for (; *s; s++) { \
d = *s - '0'; \
if (b > 10 && d > 9) \
d = tolower(*s) - 'a' + 10; \
if (d < 0 || d >= b) { \
printf("error: invalid character in number literal in base " #b "\n"); \
return 0; \
} \
px = *x; \
*x *= b; \
*x += d; \
if (*x < px) { \
printf("error : number to large\n"); \
return 0; \
} \
} \
return b; \
}
#define X(p, b) MAKE_INT_OF_BASE(b)
BASES
#undef X