## 2009-03-26

### ASCII isdigit, isalpha and isxdigit macros in ANSI C with arithmetic operations

The naïve way of defining a C macro which tests whether a character is a digit (assuming an ASCII-based character set) is `#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')`. There is a fundamental problem with this naïve definition: it evaluates its argument `c` more than once, so for example `ISDIGIT(x++)` will increment `x` by 2 in some cases. The question naturally arises if there is a macro definition `#define ISDIGIT(c) ...`, which uses `c` exactly once. Indeed, there is:
`#define ISDIGIT(c) ((c) - '0' + 0U <= 9U)`. The capital `U`s in the expression enforce unsigned calculation, so if `c` is less than `'0'`, then `(c) - '0' + 0U` becomes a large positive number instead of a negative number with small absolute value, so the comparison will (correctly) return false.

The following code contains solutions for `ISDIGIT`, `ISALPHA` and `ISXDIGIT`, the latter not being practical because of the excessive use of arithmetic operations.
`/* by pts@fazekas.hu at Thu Mar 26 01:10:56 CET 2009** 0123456789 ISDIGIT* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ISALPHA* 0123456789ABCDEF ISCAPITALHEX* 0123456789ABCDEFabcdef ISXDIGIT*/#include <stdio.h>#define ISDIGIT(c) ((c) - '0' + 0U <= 9U)#define ISALPHA(c) (((c) | 32) - 'a' + 0U <= 'z' - 'a' + 0U)#define ISCAPITALHEX(c) ((((((c) - 48U) & 255) * 23 / 22 + 4) / 7 ^ 1) <= 2U)#define ISXDIGIT(c) (((((((((c) - 48U) & 255) * 18 / 17 * 52 / 51 * 58 / 114 \     * 13 / 11 * 14 / 13 * 35 + 35) / 36 * 35 / 33 * 34 / 33 * 35 / 170 ^ 4) \     - 3) & 255) ^ 1) <= 2U)int main(int argc, char **argv) {  int i;  (void)argc; (void)argv;  for (i = 0; i < 256; ++i) if (ISDIGIT(i)) putchar(i);  printf(" ISDIGIT\n");  for (i = 0; i < 256; ++i) if (ISALPHA(i)) putchar(i);  printf(" ISALPHA\n");  for (i = 0; i < 256; ++i) if (ISCAPITALHEX(i)) putchar(i);  printf(" ISCAPITALHEX\n");  for (i = 0; i < 256; ++i) if (ISXDIGIT(i)) putchar(i);  printf(" ISXDIGIT\n");  return 0;}`