Правильное использование/включение для uint64_t в С++

Для справки, я компилирую в С++ 11.

Я начинаю писать шахматный движок, используя растровое представление доски в виде кусочно-ориентированного подхода. Похоже, что подходящий тип, который будет использоваться, - uint64_t, однако, после поиска в Интернете довольно немного, я немного не уверен в "лучшей практике" здесь.

Я начинаю определять файл .hpp для игрового поля. Во-первых, я смущен тем сходным поведением, которое демонстрирует другой код.

#include <cstdint>
uint64_t board;

и

#include <cstdint>
std::uint64_t board;

оба компилируются просто отлично. Какая разница между двумя? Лучше другого?

Кроме того, я заметил, что мне даже не нужно включать cstdint, чтобы иметь возможность использовать uint64_t:

#include <iostream>
uint64_t board;

и

#include <iostream>
uint64_t std::board;

Оба компилируются просто отлично, как и два примера cstdint выше. Таким образом, я довольно смущен относительно того, как uint64_t предполагается использовать в С++ 11, и почему все 4 из этих примеров делают то же самое. Мне сказали, что вы хотите использовать cstdint, но похоже, что iostream также предоставляет тип def? Существует ли конкретный способ "лучший/безопасный" (например, с точки зрения конфликта пространства имен)?

Ответы

Ответ 1

Заголовки <cthing> существуют в С++ как часть наследия C. Вместо того, чтобы повторно изобретать колесо, стандартная библиотека повторно использует эти полезные части стандартной библиотеки C. Теперь различия в том, что заголовки переименованы и что они должны определять свои символы в пространстве имен std. Они также могут добавлять их в глобальное пространство имен. Обратите внимание, что они могут это сделать, а не обязательно.

Это связано с тем, что эти заголовки (как детали реализации) будут содержать чистый заголовок C <thing.h> и определять символы std:: в терминах глобальных. Но на это нельзя положиться. Стандартные разработчики библиотек могут однажды решить, что они больше не будут этого делать. И если вы включили cstdint и использовали uint64_t вместо std::uint64_t, ваша программа может случайно прекратить успешное создание.

Единственная гарантия, которую вы имеете, заключается в том, что символы в пространстве имен std будут существовать. Поэтому вы должны использовать эти символы вместо глобальных.

Теперь, как часть собственной реализации, стандартная библиотека может перекрестно включать собственные заголовки внутри себя. Вполне возможно, что ваша версия включает <cstdint> для реализации <iostream>. Но опять же, это деталь реализации, а не жесткое требование стандарта С++. Если ваша версия стандартной библиотеки изменяется и больше не делает этого, ваш код не будет создан.

В заключение, чтобы сделать ваш код максимально переносимым среди разных компиляторов и стандартных реализаций библиотек:

  • Включить <cstdint> и использовать символы, которые он определяет в пространстве имен std, которые должны существовать. 1
  • Если вам нужен какой-либо символ, укажите заголовок, где он гарантированно существует в документации. Не полагайтесь на детали реализации, которые вы случайно наткнетесь.

(1) Технически для целочисленных типов фиксированной ширины допускается undefined. Это связано с тем, что стандарт знает, что не все платформы могут иметь все, что им определено. На практике вы сможете использовать их на современных настольных компьютерах.