Monday, September 22, 2008

Compile-time assertion to detect signed and unsigned types in C

I was wondering how to tell whether a given typedef was a signed or unsigned integral type (e.g. unsigned int vs signed int, size_t vs ssize_t, etc.) in C. In C++ it would be easy with a little bit of meta-programing but in C there are far fewer options when it comes to static (aka compile-time) checking. And on this one, Google didn't help me much. So I thought I'd write something, hopefully it'll be helpful to someone searching what I was trying to find.

Here is a simple trick:
#define IS_UNSIGNED_TYPE(Type) \
char ERROR_ ## Type ## _MUST_BE_UNSIGNED[((Type) -1 < 0) * -1]

Now if you call IS_UNSIGNED_TYPE(ssize_t); GCC will give you a nice error: size of array 'ERROR_ssize_t_MUST_BE_UNSIGNED' is negative, whereas with size_t it compiles fine.

For those who don't understand how this works, it's pretty simple: the two hashes (##) are used to concatenate tokens in the macro. So for instance for the case of ssize_t we have:
  char ERROR_ssize_t_MUST_BE_UNSIGNED[((ssize_t) -1 < 0) * -1]
char ERROR_ssize_t_MUST_BE_UNSIGNED[(-2147483648 < 0) * -1]
char ERROR_ssize_t_MUST_BE_UNSIGNED[1 * -1]
char ERROR_ssize_t_MUST_BE_UNSIGNED[-1] // Invalid
Whereas for size_t we have:
  char ERROR_size_t_MUST_BE_UNSIGNED[((size_t) -1 < 0) * -1]
char ERROR_size_t_MUST_BE_UNSIGNED[(4294967295 < 0) * -1]
char ERROR_size_t_MUST_BE_UNSIGNED[0 * -1]
char ERROR_size_t_MUST_BE_UNSIGNED[0] // Valid
Not particularly useful but ... Kind of neat, isn't it?


Unknown said...

如果我將此 char 的值 與 0xffffff 作 OR 運算,然後偵測是否小於 0 ,不就可知道此 char 是否為 signed 或是 unsigned 了嗎?

tsuna said...

So If I translate the previous comment via Google's language tools, it (approximately) reads:
"If I were to char and the value of the OR for 0xffffff computing, and then detect whether or not less than 0, can not know whether this char for unsigned or signed it?
Xiangliaoyixiang 1:00 am sorry, did not write a small program Test"

To which I'd answer that I don't see any benefit especially since 0xffffff is a fixed value and it's not suitable for all numeric data type (some are shorter, some are larger).

Anonymous said...

Nice brief and this mail helped me alot in my college assignement. Say thank you you as your information.

Anonymous said...

Thanks for taking the time to find the answer and publish it.. :)