Получение 32-битных слов из 64-битных значений в C/С++ и не беспокоиться о контенте

Я понимаю, что в C/С++ побитовые операторы должны быть независимыми от конца и вести себя так, как вы ожидаете. Я хочу убедиться, что я действительно получаю самые значимые и наименее значимые слова из 64-битного значения и не беспокоюсь о контенте машины. Вот пример:

uint64_t temp;
uint32_t msw, lsw;
msw = (temp & 0xFFFFFFFF00000000) >> 32;
lsw = temp & 0x00000000FFFFFFFF;

Будет ли это работать?

Ответ 1

6.5.7 Операторы побитового сдвига

4 Результат E1 < E2 - E1 сдвинутые слева позиции E2; освобождено биты заполняются нулями. Если E1 имеет беззнаковый тип, значение результатом является E1 × 2E2, приведенный по модулю один больше максимального значения представимые в типе результата. Если E1 имеет подписанный тип и неотрицательный значение и E1 × 2E2 представимо в типе результата, то это итоговое значение; в противном случае поведение undefined.

Итак, да - гарантируется стандартом.

Ответ 2

Да, это должно сработать. Когда вы извлекаете msw, ваша маска на самом деле не справляется, хотя бит, который вы маскируете до нуля, будет отброшен, когда вы все равно сделаете смену. Лично я бы, наверное, использовал что-то вроде этого:

uint32_t lsw = -1, msw = -1;
lsw &= temp;
msw &= temp >> 32;

Конечно, для создания значимого результата нужно инициализировать temp, чего не было в вашем коде.

Ответ 3

Это сработает, но странная склонность некоторых авторов к выполнению бит-маскировки перед смещением бит всегда озадачила меня.

На мой взгляд, гораздо более элегантный подход был бы тем, который делает первый сперва

msw = (temp >> 32) & 0xFFFFFFFF; 
lsw = temp & 0xFFFFFFFF; 

по крайней мере потому, что он использует ту же самую "магическую" константу бит-маски каждый раз.

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

msw = temp >> 32; 
lsw = temp; 

Ответ 4

Да. Он должен работать.

Ответ 5

Просто мысль, которую я хотел бы поделиться, возможно, вы могли бы обойти энтианность значения с помощью функций или макросов, найденных в <arpa/inet.h>, чтобы преобразовать порядок "Сеть в хост" и наоборот, можно сказать, что он больше используется в сочетании с сокетами, но его можно использовать для этого экземпляра, чтобы гарантировать, что значение, такое как 0xABCD от другого процессора, по-прежнему равно 0xABCD на Intel x86, вместо того, чтобы прибегать к пользовательским функциям с ручным кодированием для работы с endian архитектура....?!

Изменить: Здесь статья об Endianess на CodeProject, а автор разработал макросы для работы с 64 -битные значения.

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

Ответ 6

Endianness - это расположение памяти. Сдвиг - это бит (и бит-макет). Значение слова - это бит-макет, а не макет памяти. Таким образом, утверждение не имеет ничего общего со значением слова.

Ответ 7

Я думаю, что вы говорите, это правда, но где это вам?

Если у вас есть какие-то буквальные значения, которые висят вокруг, то вы знаете, к какому концу это. Но если вы окажетесь со значениями, которые появились вне программы, вы не можете быть уверены, если они не были каким-то образом закодированы.

Ответ 8

В дополнение к другим ответам, я добавлю, что вы не должны беспокоиться о контенте в проблеме C. Endianness, возникает только при рассмотрении некоторых байтов под другим типом, чем то, что использовалось для записи этих байтов в первую очередь. Когда вы это делаете, вы очень близки к проблемам с псевдонимом, что означает, что ваш код может сломаться при использовании другого компилятора или другого флага оптимизации.

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