views:

120

answers:

2

I’m trying to determine the relationship of a given compiler’s integer types’ sizes using the preprocessor. My requirement is that I have two types, one of which is unsigned, and one of which is a signed type capable of storing every positive number that said unsigned type can store. i.e. I have to ensure that my ll_ssize type can store at least as many positive and negative integers as the ll_usize can store.

Unfortunately, the exact relationships of long long and long and int aren’t defined by the C standards; on some machines (such as LP64 machines), the data storage of a long is going to be exactly equivalent to a long long.

Thus, I have to use the preprocessor to attempt to determine the largest possible type that also has a single larger type available; the unsigned version of that type becomes ll_usize, and the signed version of the larger type becomes ll_ssize.

Here is the code I’m using now:

#if defined(ULONG_MAX) && defined(LLONG_MIN) && defined(LLONG_MAX) && \
    LLONG_MIN <= -(ULONG_MAX) && ULONG_MAX <= LLONG_MAX
  typedef   unsigned    long int   ll_usize;
  typedef   signed long long int   ll_ssize;
#elif defined(UINT_MAX) && defined(LONG_MIN) && defined(LONG_MAX) && \
      LONG_MIN <= -(UINT_MAX) && UINT_MAX <= LONG_MAX
  typedef   unsigned    int   ll_usize;
  typedef   signed long int   ll_ssize;
#else
  typedef   signed int   ll_usize;
  typedef   signed int   ll_ssize;
#endif

Now, on to my problem. I can’t preform casts in preprocessor expressions, but it seems that ULONG_MAX is being incorrectly converted, as my compiler (clang on Mac OS 10.6 X Snow Leopard) spits out the following warning:

Source/Paws.o/Core/ll.h:21:15: warning: left side of operator converted from
      negative value to unsigned: -9223372036854775808 to 9223372036854775808
    LLONG_MIN <= -(ULONG_MAX) && ULONG_MAX <= LLONG_MAX
    ~~~~~~~~~ ^  ~~~~~~~~~~~~

Does anybody know of a way for me to work around this conversion error? Or, preferably, a better solution to the overall problem, because I really dislike these ugly preprocessor expressions.

Edit: I should also point out why I’m doing this, instead of just using the largest signed type available: I don’t want to waste the memory space for all of those negative integers, when I’m never going to be storing negative numbers. Specifically, the unsigned type (ll_usize) is used for the stored indexes into a linked list; however, some functions that operate on the linked list can take negative index arguments, and work from the opposite end of the linked list: those functions are declared to take ll_ssize instead. The waste is acceptable as the arguments to those functions; however, the waste for the indexes on the actual lists stored in the system is not.

A: 

How about ULONG_MAX < LLONG_MAX?

Forget that "less-than-or-equal" stuff, you want it to be strictly less than.

Anon.
Nah, it should be less than or equal to: the signed type can store everything between (-UNSIGNED_TYPE_MAX) and (+UNSIGNED_TYPE_MAX), because I need to be able to positively- and negatively-index every element.I should mention, that also doesn’t get rid of the conversion error.
elliottcable
Is it really honestly important to support systems where `ulong` is 63 bits?
Anon.
This is targeted at many, many, many platforms; I expect to support 32bit machines, possibly 128bit machines, as well as extremely-restricted embedded applications and such.On top of that, I’m just curious what the correct solution is at this point d-:
elliottcable
+4  A: 

How about -(LLONG_MIN+1) > (ULONG_MAX-1) ?

tyranid
Hm! That gets rid of the warning, but I’m not sure I understand why *both* of them need a ±1…
elliottcable
because without the +1 on the LLONG_MIN then LLONG_MIN > LLONG_MAX, the -1 just balances the equation :)
tyranid
Damn. That’s a genius solution. +1 makes it fit, -1 makes it valid again. I’d give you raw reputation if I could, for that. d-:
elliottcable
For anyone interested, this completely solved my problem, and elegantly, too: http://github.com/elliottcable/Paws.o/commit/fdfeacc1334bd42214ae9a84c737520fedf681d5
elliottcable
This actually only works if the processor uses 2s complement to store ints. Some DSPs I've used use 1s complement.
Joel
Joel: Do you have a better solution? Or a fix for this one?
elliottcable
You could make it >= rather than just >, there is still a slight edge case but I cannot think what actual integer representation you would need to have to make it an actual issue. I suppose technical anything is possible in a world where these things are terribly concrete.
tyranid
What about balancing by two instead of one? Wouldn’t that fit in *all* the various negative integer representations? At least, a quick glance at http://en.wikipedia.org/wiki/Signed_number_representations#Comparison_table makes me think it would work… but I’m no expert /-:
elliottcable