dnl -*-autoconf-*- ### SYNOPSIS ### ### dnl mdw_UINT_BITS(TYPE, ABBREV) ### ### DESCRIPTION ### ### Defines ABBREV_BITS to be the number of bits representable by the ### unsigned type named TYPE. This works even if the compiler in question ### is a cross-compiler, and correctly handles systems without 8-bit bytes, ### or which have hidden bits in their integer representations. ### ### LICENSE ### ### Copyright (c) 2013 Mark Wooding ### ### This program is free software: you can redistribute it and/or modify it ### under the terms of the GNU General Public License as published by the ### Free Software Foundation, either version 2 of the License, or (at your ### option) any later version. ### ### This program is distributed in the hope that it will be useful, but ### WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ### General Public License for more details. ### ### You should have received a copy of the GNU General Public License along ### with this program. If not, see . ### ### In particular, no exception to the GPL is granted regarding generated ### `configure' scripts which are the output of Autoconf. dnl Algorithm: dnl dnl We first find an upper bound on the number of bits in the type as dnl sizeof(TYPE) * CHAR_BIT. This is usually a good guess at the actual dnl value, since most modern systems don't have hidden bits, so we test to dnl see if it's correct. If not, we start a binary search to find the true dnl value. dnl dnl To test a guess n, we form X = (TYPE)~(TYPE)0, which is the largest value dnl representable as a TYPE, and attempt to shift it right by n places. This dnl is a little subtle, since shifting by more than the word length is dnl undefined behaviour. The implementation isn't completely perfect. It dnl assumes that a shift of 15 bits must be allowed (which is reasonable, dnl since an int must be at least 16 bits, and the standard integer dnl promotions will map shorter integer types to an int). If n > 15, we dnl shift down in two stages, once by dividing by 2^15 = 32768, and once by dnl shifting by n - 15; otherwise we just shift. (This strange chicanery is dnl to deal with Microsoft compilers which incorrectly `optimize' adjacent dnl correct shifts into a single invalid one.) If X >> n is nonzero then n dnl is too small; if X >> (n - 1) is zero then n is too large; if neither dnl condition holds then n is correct. dnl dnl This is, unfortunately, logarithmic if the initial guess is wrong, but dnl that will happen rarely on interesting platforms. Sites wanting to speed dnl up the configuration process can pre-seed the configuration cache. If dnl anyone really cares, we can detect a native compiler (as opposed to a dnl cross-compiler) and do the binary-search in C. # Serial 1 AC_DEFUN([mdw_UINT_BITS], [AC_CACHE_CHECK([size of type `$1' in bits], [mdw_cv_$2_bits], [mdw_PROBE_CONSTANT([guess], [sizeof($1) * CHAR_BIT], [ #include #ifdef HAVE_STDINT_H # include #endif]) down=0 while :; do mdw_PROBE_CONSTANT([answer], [low($guess) ? -1 : low($guess - 1) ? 0 : +1], [ #ifdef HAVE_STDINT_H # include #endif #define srs(x, n) ((n) <= 15 ? (x) >> (n) : ((x)/32768) >> ((n) - 15)) #define max (($1)~($1)0 | 0u) #define low(b) (srs(max, b) != 0) ]) case "$answer" in 0) break;; 1) up=$guess;; -1) down=$guess;; esac guess=$(expr \( $up + $down \) / 2) done mdw_cv_$2_bits=$guess]) AS_TR_SH($2_bits)=$mdw_cv_$2_bits AC_DEFINE_UNQUOTED(AS_TR_CPP([$2_BITS]), [$mdw_cv_$2_bits], [number of bits in an object of type `$1'])])