I am learning “Expert C Programming” by Peter Van Der Linden. In chapter A.6, the writter described how to determine whether a variable is unsigned or not in K&R C.The macro is below:
#define ISUNSIGNED(a) (a>=0 && ~a>=0)
The book is very old, it was first published in 1994! And I have not learned K&R C before.
The question is that how to determine whether a variable is unsigned or not in ANSI C.
I have tried to solve the problem like this. Since “0” is int in ANSI C, and any other number except float, double and long double will be converted to int or unsigned int by Integer Upgrade when compare with 0. So I want to find an edge between unsigned and signed number. When I compare (the edge type)0 with a, the type of a will not be changed. The macro also the model is below:
#define ISUNSIGNED(a) (a>=(the edge type)0 && ~a>=(the edge type)0)
I can not find the edge type, is there anybody can help me solve the problem?
I have changed “number” to “variable” for more accurate expression.
How this works
A signed variable has to store its sign in some bit. Usually this is the most significant one, but it could be any of them. An unsigned variable has no sign bits; thus, the lowest value it can hold is 0. This means that for an unsigned variable
a, the expressiona >= 0will always be true.So we have:
If
ais unsigned, the first is true (it has to be), and the second is true (because whatever value~ais, it’s still an unsigned value, so it’s still>= 0). Ifais signed, that means that if the sign bit is set,a >= 0is false (and the expression returns false, stating that this variable has a signed type). If the sign bit isn’t set ina, then when~ainverts all the bits ina, the sign bit (whichever one it is) has to be set. This means that it has to be a negative number, which means that~a >= 0returns false.This does rely on the standard integer promotions to work like you’d expect them to.
How it doesn’t work
As someone else pointed out,
unsigned chargets promoted to anintsince any value of~afor anunsigned char acan easily fit in the range of anint. This is arguably a failing in the standard integer promotions (or a failing in the typing of integral literals).There might be another implementation of
ISUNSIGNEDorISSIGNEDsomewhere that can overcome this limitation. The P99 macro library has some mind-bending uses of macros, many relying on C99’s variadic macros, but unfortunately the macro to check whether an expression is signed or not (#define SIGNED(expr) ((1 ? -1 : expr) < (1 ? 0 : expr))) succumbs to the same integer promotions. This might be the best you can do (though I suppose it’s better than nothing in the cases where you’ll want it).