Примечание: я обновил этот ответ, поскольку при более подробном изучении этой проблемы в некоторых комментариях были выявлены случаи, когда она будет определяться реализацией или даже не определяться в случае, который я не рассматривал изначально (в частности, в C ++ 17 также).
Я полагаю, что в некоторых случаях это поведение, определяемое реализацией, а в других - неопределенное (так как другой ответ пришел к выводу по аналогичным причинам).В некотором смысле это реализация, определенная, если это неопределенное поведение, или определенная реализация, поэтому я не уверен, что она вообще не определена, имеет приоритет в такой классификации.
, поскольку std::memcpy
полностью работает на объектном представлениирассматриваемые типы (путем совмещения имен указателей, присвоенных unsigned char
, как указано в 6.10 / 8.8 [basic.lval]).Если биты в рассматриваемых байтах unsigned long long
гарантированно являются чем-то конкретным, вы можете манипулировать ими по своему усмотрению или записывать их в объектное представление любого другого типа.Тип назначения будет затем использовать биты для формирования своего значения на основе его представления значения (каким бы оно ни было), как определено в 6.9 / 4 [basic.types]:
Представление объектаОбъект типа T - это последовательность из N беззнаковых объектов char, занятых объектом типа T, где N равно sizeof (T).Представление значения объекта представляет собой набор битов, которые содержат значение типа T. Для тривиально копируемых типов представление значения представляет собой набор битов в представлении объекта, которое определяет значение, которое является одним дискретным элементом реализации.определенный набор значений.
И это:
Предполагается, что модель памяти C ++ совместима с моделью языка программирования ISO / IEC 9899 C.
Зная это, все, что сейчас имеет значение, - это то, каково объектное представление рассматриваемых целочисленных типов.Согласно 6.9.1 / 7 [basic.fundemental]:
Типы bool, char, char16_t, char32_t, wchar_t, а также целочисленные типы со знаком и без знака называются целыми типами.Синоним для целочисленного типа - целочисленный тип.Представления целочисленных типов должны определять значения с использованием чисто двоичной системы счисления.[Пример: этот международный стандарт разрешает два дополнения, одно дополнение и представление величины со знаком для целочисленных типов.- конец примера]
Однако в сноске разъясняется определение "двоичной системы нумерации":
Позиционное представление для целых чисел, использующее двоичные цифры 0 и 1,в котором значения, представленные последовательными битами, являются аддитивными, начинаются с 1 и умножаются на последовательную интегральную степень 2, за исключением, возможно, бита с самой высокой позицией.(Адаптировано из Американского национального словаря по системам обработки информации.)
Мы также знаем, что целые числа без знака имеют то же представление значений, что и целые числа со знаком, только под модулем в соответствии с 6.9.1 / 4 [basic.fundemental]:
Беззнаковые целые должны подчиняться законам арифметики по модулю 2 ^ n, где n - количество бит в представлении значения этого конкретного размера целого числа.
Хотя это не говорит точно, каким может быть представление значения, на основе указанного определения двоичной системы нумерации, последовательные биты должны быть аддитивными степенями двух, как и ожидалось (вместо того, чтобы позволять битам быть в любом заданном порядке), за исключением, возможно, настоящего знака бита.Кроме того, поскольку представления значений со знаком и без знака, это означает, что целое число без знака будет храниться как возрастающая двоичная последовательность вплоть до 2 ^ (n-1) (в прошлом, в зависимости от того, как обрабатываются числа со знаком, вещи определяются реализацией).
Однако есть еще некоторые другие соображения, такие как порядковый номер байтов и количество битов заполнения, которые могут присутствовать из-за того, что sizeof(T)
измеряет только размер представления объекта, а не представление значения (как указано ранее). Поскольку в C ++ 17 не существует стандартного способа (я думаю) проверки на порядковый номер, это является основным фактором, который оставил бы эту реализацию в зависимости от того, каким будет результат. Что касается битов заполнения, хотя они могут присутствовать (но не указано, где они будут, что я могу сказать, кроме того, что они не будут прерывать непрерывную последовательность битов, образующих представление значения целого числа), запись в них может оказаться потенциально проблематичным. Поскольку цель модели памяти C ++ основана на модели памяти стандарта C99 «сопоставимым» способом, сноска из 6.2.6.2 (на которую в стандарте C ++ 20 ссылаются как на примечание, чтобы напомнить, что она основана на том, что ) можно сказать следующее:
Некоторые комбинации битов заполнения могут генерировать представления ловушек,
например, если один бит дополнения является битом четности. Независимо от того, нет
арифметическая операция над допустимыми значениями может генерировать ловушку
представление, кроме как как часть исключительного условия, такого как
переполнение, и это не может произойти с неподписанными типами. Все остальные
комбинации битов заполнения являются альтернативными объектными представлениями
значение, указанное битами значения.
Это подразумевает, что неправильная запись непосредственно в биты заполнения может потенциально генерировать представление ловушки из того, что я могу сказать.
Это показывает, что в некоторых случаях, в зависимости от наличия битов заполнения и порядкового номера, на результат можно влиять способом, определяемым реализацией. Если некоторая комбинация битов заполнения также является представлением прерывания, это может стать неопределенным поведением.
Хотя это невозможно в C ++ 17, в C ++ 20 можно использовать std::endian
в сочетании с std::has_unique_object_representations<T>
(который присутствовал в C ++ 17) или некоторую математику с CHAR_BIT
, UINT_MAX
/ ULLONG_MAX
и sizeof
этих типов для обеспечения правильности ожидаемого порядка байтов, а также отсутствия битов заполнения, что позволяет на самом деле получить ожидаемый результат определенным образом, учитывая то, что ранее было установлено с тем, как говорят целые числа храниться Конечно, C ++ 20 также дополнительно уточняет это и указывает, что целое число должно храниться только в двух дополнениях, что устраняет дальнейшие проблемы, связанные с реализацией.