27

For reference, I am compiling in C++11.

I am getting started on writing a chess engine using a bitmap representation of the board as a piece-centric approach. It seems like the suitable type to be using is uint64_t , however, after searching online quite a bit, i am a bit unsure about the "best practice" here.

I am beginning to define the .hpp file for the game board. Firstly, I am confused about the similar behavior that different code seems to exhibit.

#include <cstdint>
uint64_t board;

and

#include <cstdint>
std::uint64_t board;

both compile just fine. What is the difference between the two? Is one better than the other?

Additionally, I've noticed that I don't even need to include cstdint to be able to use uint64_t :

#include <iostream>
uint64_t board;

and

#include <iostream>
uint64_t std::board;

Both compile just fine, like the 2 cstdint examples above. As such, I am quite confused as to how uint64_t is supposed to be used in C++11, and why all 4 of those examples all do the exact same thing. I was told that you want to use cstdint , but it seems like iostream provides the type def as well? Is there a specific way that is the "best/safest" (for example in terms of namespace conflict)?

hundred_dolla_tea
  • 523
  • 1
  • 5
  • 14
  • 2
    Related: [ vs ](https://stackoverflow.com/questions/13642827/cstdint-vs-stdint-h) and [Why can std::max and std::min still be used even if I didnt #include ?](https://stackoverflow.com/questions/19897722/why-can-stdmax-and-stdmin-still-be-used-even-if-i-didnt-include-algorithm) – chwarr Jun 21 '17 at 07:49

1 Answers1

31

The <cthing> headers exist in C++ as part of its C heritage. Rather than re-invent the wheel, the standard library reuses these useful parts of the C standard library. Now, the differences are that the headers are renamed, and that they must define their symbols in namespace std. They also may add them to the global namespace. Note that they may do so, not must.

This is because those headers (as an implementation detail) will include the pure C header <thing.h> and define the std:: symbols in terms of the global ones. But that is not something you can rely on. Standard library implementors may one day decide that they will no longer do it like that. And if you included cstdint and used uint64_t instead of std::uint64_t, your program may randomly stop building successfully.

The only guarantee you have, is that the symbols in the std namespace will exist. So you should use those symbols instead of the global ones.

Now, as part of its own implementation, the standard library may cross-include its own headers within itself. It's quite possible that your version includes <cstdint> in order to implement <iostream>. But again, this is an implementation detail and not a hard requirement by the C++ standard. If your version of the standard library changes, and no longer does that, your code will fail to build.

In summary, to make your code as portable as possible among different compilers and standard library implementations:

  1. Include <cstdint> and use the symbols it defines in namespace std, those are required to exist.1
  2. If you need any symbol, include the header where it's guaranteed to exist by the documentation. Don't rely on implementation details you stumble upon by accident.

(1) Technically the fixed width integer types are allowed to be undefined. This is because the standard is aware that not all platforms can have all off them defined. In practice, you'll have them all available on modern desktop machines.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    Wonderfully explained answer and very helpful, thank you. – hundred_dolla_tea Jun 21 '17 at 07:08
  • IIRC, ISO C++ still reserves type names ending with `_t` in the global namespace, so it seems to me like more of an annoyance that they don't guarantee that global-scope `uint64_fast64_t` is usable in pure ISO C++, instead having to clutter things with `std::uint_fast64_t`. (But not `std::int` or `std::long`). Portable code can't safely define `uint_fast64_t` or any other `_t` type itself. – Peter Cordes Dec 18 '21 at 01:46
  • 1
    @PeterCordes - That's a POSIX restriction, not a C++ or C one. – StoryTeller - Unslander Monica Dec 18 '21 at 01:48
  • Ah, thanks, that's a lot less dumb, then. (The end result is still annoying, worst of both worlds, IMO. But at least it makes sense how we got here. :/) – Peter Cordes Dec 18 '21 at 01:48