what would be the most portable way to test if UINT_MAX>=0xFFFFFFFwith the preprocessor?

F

Francois Grieu

I have code on the tune of

#include <limits.h>

#if 0xFFFFFFFF>=UINT_MAX
typedef unsigned int tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "" /* printf prefix for tu32 (none) */
#else
typedef unsigned long tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "l" /* printf prefix for tu32 */
#endif


It works on all current versions of compilers I use (one of which is 8
years old, and many claim only C89 compatibility, plus a few extensions
like // comments).

However, I am concerned that when UINT_MAX is 0xFFFF, some old preprocessors
might evaluate 0xFFFFFFFF>=0xFFFF as if it was -1>=0xFFFF, and thus take the
wrong branch. From memory, this has hit me once, though I can't pinpoint a
culprit.

Does one know a compiler/preprocessor where #if 0xFFFFFFFF>=UINT_MAX would
not work correctly?

What would be the safest way? What about #if UINT_MAX>>30 >= 3 ?


TIA,

Francois Grieu
 
T

Tim Rentsch

Francois Grieu said:
I have code on the tune of

#include <limits.h>

#if 0xFFFFFFFF>=UINT_MAX
typedef unsigned int tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "" /* printf prefix for tu32 (none) */
#else
typedef unsigned long tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "l" /* printf prefix for tu32 */
#endif

It looks like the comparison in the #if is turned around. Am I
misunderstanding what you're trying to do?
It works on all current versions of compilers I use (one of which is 8
years old, and many claim only C89 compatibility, plus a few extensions
like // comments).

However, I am concerned that when UINT_MAX is 0xFFFF, some old preprocessors
might evaluate 0xFFFFFFFF>=0xFFFF as if it was -1>=0xFFFF, and thus take the
wrong branch. From memory, this has hit me once, though I can't pinpoint a
culprit.

Does one know a compiler/preprocessor where #if 0xFFFFFFFF>=UINT_MAX would
not work correctly?

What would be the safest way? What about #if UINT_MAX>>30 >= 3 ?

I would probably use -1U >> 15 >> 15 >= 3

It's possible that the shift of 30 is guaranteed to
work in #if because of special rules for how arithmetic
is done in the preprocessor, but I'm not sure older
compilers should be trusted to get that right (even
assuming the guarantee holds, which I'm not sure it
does for C89/C90).

Also, using two shifts of only 15 each means the same
expression can be used portably in regular code and not
just the preprocessor, which obviously has a certain
amount of appeal, and also some value (eg, if this test
is made available as a macro which might be used in an
'if()' in addition to #if).
 
F

Francois Grieu

It looks like the comparison in the #if is turned around. Am I
misunderstanding what you're trying to do?

You read my mind. The code actually contains #if 0xFFFFFFFF<=UINT_MAX
and this mess is me trying to make it look like the title of the post.

I would probably use -1U>> 15>> 15>= 3

I think that the preprocessor part of cross-compilers is allowed
to use wider types than their target. 1U can be 64-bit as far
as the preprocessor is concerned, even if UINT_MAX is 0xFFFF,
right?

At least, I met preprocessors which perform all their arithmetic
over 32 bits, even though the compiler does not. In these
#if ( 256<<8 ) is taken
if ( 256<<8 ) is not taken
and this is NOT a non-conformance AFAIK.
It's possible that the shift of 30 is guaranteed to
work in #if because of special rules for how arithmetic
is done in the preprocessor, but I'm not sure older
compilers should be trusted to get that right (even
assuming the guarantee holds, which I'm not sure it
does for C89/C90).
Also, using two shifts of only 15 each means the same
expression can be used portably in regular code and not
just the preprocessor, which obviously has a certain
amount of appeal, and also some value (eg, if this test
is made available as a macro which might be used in an
'if()' in addition to #if).

Good catch. #if UINT_MAX>>15>>15 >= 3

Francois Grieu
 
T

Tim Rentsch

Francois Grieu said:
Francois Grieu said:
I have code on the tune of

#include<limits.h>

#if 0xFFFFFFFF <= UINT_MAX /* [incorporate correction] */
typedef unsigned int tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "" /* printf prefix for tu32 (none) */
#else
typedef unsigned long tu32; /* unsigned at-least-32-bit type */
#define P_TU32 "l" /* printf prefix for tu32 */
#endif

It works on all current versions of compilers I use (one of which is 8
years old, and many claim only C89 compatibility, plus a few extensions
like // comments).

However, I am concerned that when UINT_MAX is 0xFFFF, some old preprocessors
might evaluate 0xFFFFFFFF>=0xFFFF as if it was -1>=0xFFFF, and thus take the
wrong branch. From memory, this has hit me once, though I can't pinpoint a
culprit.

Does one know a compiler/preprocessor where #if 0xFFFFFFFF>=UINT_MAX would
not work correctly?

What would be the safest way? What about #if UINT_MAX>>30>= 3 ?

I would probably use -1U >> 15 >> 15 >= 3

I think that the preprocessor part of cross-compilers is allowed
to use wider types than their target. 1U can be 64-bit as far
as the preprocessor is concerned, even if UINT_MAX is 0xFFFF,
right?

At least, I met preprocessors which perform all their arithmetic
over 32 bits, even though the compiler does not. In these
#if ( 256<<8 ) is taken
if ( 256<<8 ) is not taken
and this is NOT a non-conformance AFAIK.

You're right, and actually it's worse than just a cross-platform
concern -- in a preprocessor expression, -1U will have at least
32 bits regardless of the size of unsigned int. So using
UINT_MAX is right, -1U is wrong. Thank you for pointing out
this problem.


I went back and checked and this guarantee holds even under
C89/C90, modulo the earlier compilers getting it right of
course.
Good catch. #if UINT_MAX>>15>>15 >= 3

Glad to be of service. :)
 
J

Jens Gustedt

Am 03/29/2012 07:49 AM, schrieb Francois Grieu:
I think that the preprocessor part of cross-compilers is allowed
to use wider types than their target. 1U can be 64-bit as far
as the preprocessor is concerned, even if UINT_MAX is 0xFFFF,
right?

At least, I met preprocessors which perform all their arithmetic
over 32 bits, even though the compiler does not. In these
#if ( 256<<8 ) is taken
if ( 256<<8 ) is not taken
and this is NOT a non-conformance AFAIK.

Since C99 the preprocessor arithmetic must be the one of {u}intmaxt_t
for the target platform. So your example is well possible.

The #-comparison is done in intmax_t and goes ok.

The other one is done with int. If int has only 16 bit 256<<8 is an
overflow and thus the behavior is undefined.

Jens
 
F

Francois Grieu

I do the equivalent of 'make main' with

main: main.c local.h
cc -o main main.c
local.h: local
local >local.h
local: local.c
cc -o local local.c

where local.c might include things like

if (sizeof(int)==4) {
if (UINT_MAX>=0xFFFFFFFF)
printf("typedef unsigned int tu32\n#define P_TU32 \"\"\n");
else
printf("typedef unsigned long tu32\n#define P_TU32 \"l\"\n");
}else
printf("typedef unsigned long tu32\n#define P_TU32 \"l\"\n");

One problem is: many of my target are "freestanding" environments (as
defined by ISO/IEC 9899:1999 section 4p6), thus do not have printf.
I do have check made by the compiler (at compile time) that tu32
has the correct behavior; something like:

#define ASSERT_S(cond) extern char assert__failure[0!=(cond)?1:-1];
ASSERT_S( (tu32)0-(tu32)1 == 0xFFFFFFFFL );


Francois Grieu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top