Целочисленные типы для использования в переносимой библиотеке C++

Я поддерживаю библиотеку с открытым исходным кодом, которая должна работать на нескольких платформах и предлагает (среди прочего) математические процедуры для нативных типов данных. Мы хотим предлагать 64-битные вычисления везде, где это возможно.

Нашими целевыми платформами являются Linux и OSX на 32-битной и 64-битной версиях, Windows еще не поддерживается, но известно, что большая часть кода работает под Windows, и поэтому мы сохраняем возможность легкого переноса на Windows в недалеком будущем. будущее. Следовательно, что касается http://en.cppreference.com/w/cpp/language/types, нас интересуют ILP32, LLP64 и LP64. Мы также взаимодействуем с gmp (который предлагает конструкторы только для int и long, но не для long long).

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

  • Если мы используем int, мы возвращаемся к 32 битам на 64-битных платформах.
  • Если мы используем long, у нас будет противоречивое поведение между Linux/OSX 64 и Windows 64: Windows не сможет использовать 64-битные вычисления.
  • Если мы используем long long, использование gmp превращается в беспорядок, потому что создание mpz_class из long long приводит к неоднозначной перегрузке. Нам пришлось бы заранее привести числа обратно к long (и, таким образом, эффективно использовать только 32 бита в Windows в ряде мест).
  • Если мы используем std::int64_t и подобные, определения типов различаются между платформами, и, таким образом, мы получаем одни и те же проблемы, просто разные для каждой платформы...

Есть ли какая-то лучшая практика для этого? Можно ли вообще избежать этих проблем или они присущи системе типов C++?

Конечно, на этом проблемы не заканчиваются. Дополнительные открытые вопросы для рассмотрения:

  • Как каждое из этих решений взаимодействует, например, с std::size_t? std::size_t имеет свою цель, но иногда ему нужно взаимодействовать с числами, на которых мы рассчитываем. Очевидно, мы не хотим все время метаться туда-сюда.
  • Как мы справляемся с использованием других типов номеров? Если мы предлагаем функцию f(T) и предоставляем перегрузки для T = int,long,long long, но пользователь использует ее с std::int64_t, можем ли мы избежать непоследовательного поведения между различными платформами? (которые имеют разные определения std::int64_t) Если мы также предоставим перегрузки для std::int64_t, у нас будут повторяющиеся перегрузки.

PS: я уже прочитал c-long-long-int -vs-long-int-vs-int64-t и следует-я-использую-long-long-or-int64-t-for-portable-code. Я получил некоторое представление о том, что именно происходит и почему это так, но не смог найти решение...


person nafur    schedule 21.03.2016    source источник
comment
Не уверен, в чем вопрос. std::int64_t — это 64-битный целочисленный тип в любой соответствующей реализации. std::size_t не должно иметь никакого отношения к вашим числам, это тип для выражения размера объекта, ничего больше, ничего больше. И последнее, но не менее важное: никогда не используйте long, если есть какая-либо попытка переносимости. Это самый изменчивый тип. Я даже знаю среду, в которой long проверяется при типе регистрации, и наличие этого в вашем коде является блоком для регистрации.   -  person SergeyA    schedule 21.03.2016
comment
@SergeyA Проблема с семейством типов intN_t в том, что они не должны существовать.   -  person NathanOliver    schedule 21.03.2016
comment
@NathanOliver, OP упоминает OS X, Linux и Windows. Они существуют в основных реализациях C++, используемых на этих платформах.   -  person SergeyA    schedule 21.03.2016


Ответы (1)


Похоже, ваш gmp в Windows по определению никогда не будет поддерживать 64-битные значения. Поэтому я предлагаю просто использовать int64_t в вашем коде, и в любое время, когда вам нужно взаимодействовать с gmp, сначала static_cast значение long.

person Mark B    schedule 21.03.2016