[issue10325] PY_LLONG_MAX & co - preprocessor constants or not?

Hallvard B Furuseth report at bugs.python.org
Fri Nov 5 14:56:12 CET 2010


New submission from Hallvard B Furuseth <h.b.furuseth at usit.uio.no>:

Include/pyport.h invites potential compile errors with the definitions
  #define PY_LLONG_MIN LLONG_MIN
  #define PY_LLONG_MAX LLONG_MAX
  #define PY_ULLONG_MAX ULLONG_MAX
which can fall back to gcc variants or to
  #else
  /* Otherwise, rely on two's complement. */
  #define PY_ULLONG_MAX (~0ULL)
  #define PY_LLONG_MAX  ((long long)(PY_ULLONG_MAX>>1))
  #define PY_LLONG_MIN (-PY_LLONG_MAX-1)

Code developed with the former #definitions might use them in '#if's,
and then break when it meets a host where the fallbacks are used.

It would be safer if either all the macros and pyconfig variants used
casts, or all used predefined constants - from configure if needed.

The signed variants would break because '#if's do not accept casts.

PY_ULLONG_MAX is more insidious: If it meets a host which supports
a type bigger than unsigned long long, then preprocessor arithmetic
will happen in that type. ~0ULL in #if statements is then actually
the same as ~ULLL or whatever it would be spelled.  This one
definitely needs a cast to protect from the surprise that
preprocessor value != value outside preprocessor.

You get the same effect with ~0U vs ~0UL on a 64-bit compiler,
and ~0U vs ~0ULL on a C99 compiler:
#if (~0U) == (~0ULL)
# error "oops"
#endif

Incidentally, the "two's complement" comment is wrong.
It also relies on unsigned long long being widest type with no
padding bits, and -LLONG_MAX-1 not being a trap representation.
~0ULL is not two's complement since it is unsigned, it works
because it has the same result as -1ULL which is defined to
have the max value.
The PY_LLONG_MIN definitions rely on two's complement. If
anyone cared, one could avoid that with
#define PY_LLONG_MIN (-PY_LLONG_MAX-(/*two's complement*/(-1LL & 3)==3))


Anyway.  If they use casts, fix PY_TIMEOUT_MAX in 3.2a3 pythread.h:
#define PY_MIN(x, y) ((x) < (y) ? (x) : (y))
#define PY_TIMEOUT_MAXTMP instead of PY_TIMEOUT_MAX, and then
#ifndef NT_THREADS
#define PY_TIMEOUT_MAX PY_TIMEOUT_MAXTMP
#else
#define PY_TIMEOUT_MAX PY_MIN(Py_LL(0xFFFFFFFF)*1000, PY_TIMEOUT_MAXTMP)
#endif

----------
components: Interpreter Core
messages: 120492
nosy: hfuru
priority: normal
severity: normal
status: open
title: PY_LLONG_MAX & co - preprocessor constants or not?
type: compile error
versions: Python 2.6, Python 2.7, Python 3.1, Python 3.2

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue10325>
_______________________________________


More information about the Python-bugs-list mailing list