Tim Rentsch said:
Ben Bacarisse said:
Rahul wrote:
[...]
2.and in what scenarios should I define a character as unsigned?
You shouldn't. If you know that it is a character, use char. Only use
unsigned char if you're storing numbers rather that characters.
Well, mostly. The is*() and to*() functions in <ctype.h> expect
arguments representable as an unsigned char (or the value EOF).
Wishy-washy-signedness of chars is full of traps - your list isn't
exaustive.
Once can reduce to:
#define xxx_ctype_invoke(f, a) f((unsigned int)a)
#define xislower(a) xxx_ctype_invoke(islower, a)
#define xisupper(a) xxx_ctype_invoke(isupper, a)
How does that help? It may just be insufficient coffee, but i can't
see how converting a signed char to a large positive number meets the
requirements imposed by the ctype functions. In fact, it seems to add
another problem if the large unsigned value can't be represented as an
int. That's not UB, but since the conversion can do anything
including raising a signal it is almost as troublesome as UB.
It guards against accidentally forgetting the calling
requirements of the isXXX functions, which specify
taking a character argument that's been converted to (unsigned char)
(and perhaps thence to (int), but that's done automatically
by the calling conversions). Any (char) is representable as
an (unsigned char).
I know the /intent/ of the code, it was the /effect/ I was having
trouble with.
Given char c; when char is signed and c holds a negative value,
islower(c) is an error. I think we both agree up to this point. I
think we also agree that islower((unsigned char)c) is safe and
correct.
I am having trouble with islower((unsigned int)c). Surely the
unsigned int that results from this cast might not even be
representable as an int (the type given in the prototype for islower).
Even if this conversion from unsigned int to int passes your
portability requirements, the value is very unlikely to be "an int, the
value of which shall be representable as an unsigned char" as required
by the ctype functions.