[New-bugs-announce] [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
/* 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"
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
#define PY_TIMEOUT_MAX PY_TIMEOUT_MAXTMP
#define PY_TIMEOUT_MAX PY_MIN(Py_LL(0xFFFFFFFF)*1000, PY_TIMEOUT_MAXTMP)
components: Interpreter Core
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>
More information about the New-bugs-announce