I get the error
‘CHAR_WIDTH’ undeclared
when I try to compile this simple program:
#include <stdio.h>
#include <limits.h>
int main()
{
printf("CHAR_BIT = %d\n", CHAR_BIT);
printf("CHAR_WIDTH = %d\n", CHAR_WIDTH);
return (0);
}
with
gcc ./show_char_width.c -o show_char_width
and gcc: GNU C17 (Ubuntu 8.3.0-6ubuntu1) version 8.3.0 (x86_64-linux-gnu) compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP, kernel: 5.0.0-37-generic.
As stated here CHAR_WIDTH should be defined in limits.h which is included in my program. So why I get this error?
With the -v
option I found that the library will be searched in those directories:
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed contain a limits.h that include syslimits.h from the same dir which in turn include the next limits.h, that from my understanding should be located in the /usr/include directory.
The CHAR_WIDTH macro is indeed defined in those files but under some conditions that exceed my actual knowledge.
The conditions I found untill now are:
/* The integer width macros are not defined by GCC's <limits.h> before
GCC 7, or if _GNU_SOURCE rather than
__STDC_WANT_IEC_60559_BFP_EXT__ is used to enable this feature. */
#if __GLIBC_USE (IEC_60559_BFP_EXT)
# ifndef CHAR_WIDTH
# define CHAR_WIDTH 8
# endif
and :
#ifdef __STDC_WANT_IEC_60559_BFP_EXT__
/* TS 18661-1 widths of integer types. */
# undef CHAR_WIDTH
# define CHAR_WIDTH __SCHAR_WIDTH__
That's why I need your help.
Note: I get the same error with all other macros described in A.5.1 notably: SCHAR_WIDTH, INT_WIDTH, LONG_WIDTH, etc.
CHAR_WIDTH
isn't standard, nor are any other *_WIDTH
macros, but the width of a character type must be the same as CHAR_BIT
anyway*.
As for *_WIDTH
macros in general, they aren't strictly needed as they are compile-time-computable from the maximum value of the corresponding unsigned type, i.e., you can have a #define WIDTH_FROM_UNSIGNED_MAX(UnsignedMax)
that expands to an integer constant expression that's also usable in preprocessor conditionals (#if
), though implementations are a little bit obscure (see Is there any way to compute the width of an integer type at compile-time?), e.g.:
#define WIDTH_FROM_UNSIGNED_MAX(UnsignedMax) POW2_MINUS1_BITS_2039(UnsignedMax)
/* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */
#define POW2_MINUS1_BITS_2039(X) ((X)/((X)%255+1) / 255%255*8 + 7-86/((X)%255+12))
//compile-time test it, assuming uint{8,16,32,64}_t exist
#include <inttypes.h>
#if WIDTH_FROM_UNSIGNED_MAX(UINT8_MAX) != 8
#error
#endif
#if WIDTH_FROM_UNSIGNED_MAX(UINT16_MAX) != 16
#error
#endif
#if WIDTH_FROM_UNSIGNED_MAX(UINT32_MAX) != 32
#error
#endif
#if WIDTH_FROM_UNSIGNED_MAX(UINT64_MAX) != 64
#error
#endif
Some people just do CHAR_BIT * sizeof(integer_type)
, but that isn't strictly portable, because it assumes integer_type
doesn't have padding bits (it usually doesn't but theoretically it can have them), and can't use it in #if
conditionals either.
*Unfortunately, to glean this info, you need jump all over the standard:
The width of an integer type is (slightly indirectly) defined as the number of its nonpadding bits (6.2.6.2p6).
6.2.6.2p2 says signed char
doesn't have any padding bits. Because of how integers can be represented in C (6.2.6.2p2), that implies unsigned char
can't have any padding bits either, and since char
must have the same limits as either signed char
or unsigned char
(5.2.4.2.1p2) while having the same sizeof
value (namely 1, 6.5.3.4p4), a plain char
can't have any padding bits either, and so CHAR_BIT
== width of (char
|signed char
|unsigned char
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With