views:

560

answers:

5

I was just checking an answer and realized that CHAR_BIT isn't defined by headers as I'd expect, not even by #include <bitset>, on newer GCC.

Do I really have to #include <climits> just to get the "functionality" of CHAR_BIT?

+2  A: 

Define "newer". A random Linux system gave me these results:

~> gcc --version
gcc (GCC) 4.1.2 (Gentoo 4.1.2)
[snip]

~> grep CHAR_BIT /usr/include/*.h
/usr/include/limits.h:#  define CHAR_BIT        8

Doesn't that qualify? In C, I think it should always be enough to include limits.h to get CHAR_BIT.

unwind
A: 

Yes, you should #include <limits.h> to get the definition of CHAR_BIT. It's not a bottleneck at all for your program (see comment below), and later down the line you might find yourself porting to different platforms. Not every implementation has the value of 8

Xavier Ho
It's not a bottleneck for your program at all, since it's a macro that expands almost invariably to a constant. All the "work" happens at compile time.
Chris Lutz
Yes, I am aware of that. Fixed the wording now. Thanks.
Xavier Ho
+3  A: 

<climits> is where CHAR_BIT is required to be by the C++ standard. Even if you happened to find it in <bitset>, its not guaranteed to be there, so you're better off going straight to the source. Its not like there's something wrong with including <climits>.

Dennis Zickefoose
+7  A: 

As you may know, whether or not an implementation wants to include other headers is unspecified. It's allowed, but not mandated. (§17.4.4.1)

The only time a C++ header must include another is if it requires a definition in another. For example, <bitset> is required to include <cstddef> for size_t, as this is explicitly stated in the standard. (§23.3.5, for this example)

For a counter-example, consider <limits>. It might include <climits> to be able to define the values for numeric_limits and it often does, since that's easiest for an implementation. But all the standard says is things like "Equivalent to CHAR_MIN, SHRT_MIN, FLT_MIN, DBL_MIN, etc." but doesn't say it has to be implemented in terms of those, which means <climits> doesn't have to be included.

So the only way you can be guaranteed that a CHAR_BIT is defined is by including <climits> or some other header where it's explicitly stated it must include it. And as far as I can tell, none have to; an implementation is free to just hard-code the value, for example, or include <limits> and use std::numeric_limits<unsigned char>::digits (which is equivalent), which as stated above doesn't necessary include <climits>

GMan
You even answered the question in the title, and provided a better name for it!
Potatoswatter
Mostly unimportant trivia: Note that an implementation including other standard headers is allowed only for C++. In C, a compiler implementation is only permitted to define `CHAR_BIT` if `limits.h` is included. In fact, if `limits.h` isn't included by the user, it's perfectly OK (by the C standard) for the user to define `CHAR_BIT` himself for his own use - that identifier is only reserved if `limits.h` is included. Not that I'd advocate that as a good idea, but it's OK as far as the C standard is concerned.
Michael Burr
Important trivia: `numeric_limits<char>::digits` is equivalent to `CHAR_BIT` only if `char` is unsigned. If `char` is signed, then it's equivalent to `(CHAR_BIT - 1)`, since the `digits` member doesn't count the sign bit. I'd just go ahead and `#include <limits.h>` to get the number you want.
Michael Burr
@Michael: You can do `unsigned char` like in the answer for the equivalent, too.
GMan
@GMan: I just wanted to specifically call out that you have to take care to use `unsigned char` and not just `char`.
Michael Burr
@Michael: Ah, gotcha. :) One could also do `numeric_limits<char>::digits + numeric_limits<char>::is_signed`, but meh.
GMan
+1  A: 

I keep the following function in my .profile to check compiler defined constants. On my system __CHAR_BIT__ is in there, which means no header is required if you can live with the double underscore form, which may only work with gcc.

defines () 
{ 
    touch /tmp/defines.h;
    cpp -dD "$@" /tmp/defines.h | awk '$1!="#"{COUNT+=1;print;}END{printf("count %d\n",COUNT);}' | sort;
    rm /tmp/defines.h
}
drawnonward
So you've got a platform-specific workaround to avoid including a header that was only required in order to avoid making assumptions about the platform in the first place?
jalf
It answers the question. Is gcc a platform?
drawnonward