Как извлечь четыре беззнаковых коротких целых числа из одного длинного длинного целого?

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

Конкретный порядок здесь особого значения не имеет.

Обычно я знаю, что мне нужно сдвинуть биты и усечь до размера unsigned short int. Но я думаю, что могу где-то совершить какую-то странную ошибку, поэтому спрашиваю.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
2 335
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

#include <stdint.h>
#include <stdio.h>

union ui64 {
    uint64_t one;
    uint16_t four[4];
};

int
main()
{
    union ui64 number = {0x123456789abcdef0};
    printf("%x %x %x %x\n", number.four[0], number.four[1],
                            number.four[2], number.four[3]);
    return 0;
}

Будет ли на это влиять прямой / прямой порядок байтов?

slashmais 29.09.2008 14:59

Да, вы получаете разные результаты для систем с прямым порядком байтов и с прямым порядком байтов.

Chris Jester-Young 29.09.2008 15:03

Это определенно быстрое и хакерское решение в том же порядке, что и: «@numbers = unpack 'S4', pack 'Q', $ number;» в Perl

Chris Jester-Young 29.09.2008 15:04

Будет неприятно терпеть неудачу, например, Cray и TI DSP, чтобы назвать лишь несколько процессоров, у которых короткое / может быть 32 бита.

MSalters 29.09.2008 15:43

Я на 100% согласен с тем, что это решение вообще не переносимо. Возможно, мне следует изменить ответ, чтобы использовать inttypes.h. :-)

Chris Jester-Young 29.09.2008 15:47

union LongLongIntToThreeUnsignedShorts {
   long long int long_long_int;
   unsigned short int short_ints[sizeof(long long int) / sizeof(short int)];
};

Это должно делать то, о чем вы думаете, без необходимости возиться с битовым смещением.

Можете ли вы гарантировать, что в структуре не будет отступов между короткими целыми числами?

Alexander 29.09.2008 14:48

Упс - изначально я писал о трех беззнаковых int. Это, вероятно, введет вас в заблуждение. Простите за это. В любом случае ваш ответ был полезен.

Paweł Hajdan 29.09.2008 14:50

Первоначально это было <code> unsigned short int </code> (вероятно, по 2 байта - это нормально). Я хотел сказать, что эта структура опасна, если вы не уверены в правилах заполнения / выравнивания.

Alexander 29.09.2008 14:55

(unsigned short)((((unsigned long long int)value)>>(x))&(0xFFFF))

где value - это ваш long long int, а x - это 0, 16, 32 или 48 для четырех шорт.

Загвоздка со сдвигом битов заключается в том, что в C / C++ поведение отрицательных чисел не определено.

Alexander 29.09.2008 14:52

Для отрицательного «значения» оно не является неопределенным, оно определяется реализацией. Для отрицательного «x» он не определен, но здесь этого никогда не происходит. И формат хранения отрицательного целого числа также определяется реализацией (в пределах определенных возможностей), так что с этой точки зрения это не хуже, чем использование объединения.

Steve Jessop 29.09.2008 15:04

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

moonshadow 29.09.2008 15:11

Я думаю, что Александр указывает на то, что результат сдвига вправо для отрицательного количества со знаком не обязательно должен быть заполнен нулем или знаком. Это может быть что угодно, если компилятор документирует что. По крайней мере, на C++. Стандарт C. Я тоже не проверял. Однако по поводу «почти всех» компиляторов вы правы.

Steve Jessop 29.09.2008 15:15

Вы меня поняли: правильная формулировка стандарта - «определяется реализацией». Я думаю, что самое простое решение для решения в этом ответе - сначала преобразовать значение в беззнаковые типы. Тогда решение превосходит структуры, потому что оно дает одинаковые результаты для архитектур с прямым и обратным порядком байтов.

Alexander 29.09.2008 15:16

«определяется реализацией» означает, что компилятор C++ в принципе может генерировать код, который, скажем, ничего не делает, если левая часть оператора сдвига вправо отрицательна.

Alexander 29.09.2008 15:18

Это позаботится, по крайней мере, о проблеме little / big-endian в ответах на основе объединения

slashmais 29.09.2008 15:18

Я понимаю, что на самом деле в большинстве компиляторов сдвиг вправо либо заполняет левые биты значением 0, либо распространяет знак, но лучше на всякий случай сначала преобразовать «значение» в беззнаковое.

Alexander 29.09.2008 15:19

Да, я бы тоже так сделал - преобразование со знаком -> без знака определено (по крайней мере, в C++, я еще не проверил C). Таким образом, результат везде одинаковый, при условии, что типы имеют ожидаемые значения MIN / MAX.

Steve Jessop 29.09.2008 15:24

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

moonshadow 29.09.2008 15:26

@SteveJessop: Интересно, есть ли какая-то особая причина, по которой правила Стандарта для смещения отрицательных чисел вправо или принуждения больших значений к малоразмерным типам со знаком не определяют никаких поведенческих требований? Насколько я могу судить, для реализации было бы вполне законно указать, что для всех отрицательных x x>>y даст 42 или y, или вычислит число любым способом, который нравится автору реализации, без побочных эффектов, x>>y с отрицательным x по существу бесполезен в строго соответствующем коде, даже если такой код будет одинаково доволен ...

supercat 12.08.2015 20:21

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

supercat 12.08.2015 20:21

@supercat: Я полагаю, это потому, что они не хотели предотвращать реализации, просто используя код операции сдвига архитектуры, и по какой-то причине не были уверены, что могут предоставить список опций, который будет включать все «удаленно нормальные» текущие и будущие архитектуры. Текущая ситуация такова, что эти строго соответствующие программы должны проверять, является ли целое число отрицательным перед сдвигом, если программист не знает, что это неотрицательно. В любой архитектуре, где код операции сдвига не обеспечивает согласованного поведения, компилятор должен будет выдать код для проверки всех сдвигов.

Steve Jessop 13.08.2015 12:37

@SteveJessop: имеет смысл определять поведение для архитектур с дополнением единиц или знаковой величиной, поскольку есть преимущества в том, что реализация действует на представление числа, но есть также преимущества в вычислении того же значения, что и архитектура с дополнением до двух, когда это возможно (приведение uint-to-int-to-uint в соответствии с такими правилами будет возвращать все значения, кроме UINT_MAX / 2, а подписанный сдвиг вправо будет предлагать семантику полового деления, которая отличается от таковой для подписанного деление способами, которые часто бывают полезными). Также могут быть случаи ...

supercat 13.08.2015 19:04

... где альтернативные вычисления могут быть полезны в реализации, которая использует математику с дополнением до двух, но имеет разное заполнение для подписанных и беззнаковых чисел. Однако для реализации, в которой используются целые числа с дополнением до двух без заполнения, единственным правдоподобным вариантом, который я мог представить в аппаратном обеспечении, было бы отсутствие сдвига вправо с расширением со знаком (и я видел подобное оборудование), и даже если знак -расширение сдвига вправо требовало большего количества кода, чем расширение без знака, я считаю, что x = (int)((unsigned)x>>1) не менее понятен, чем x>>1 в случае, когда ...

supercat 13.08.2015 19:11

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

supercat 13.08.2015 19:17

... соблюдает ли компилятор это соглашение и определяет условия, связанные с соответствием, для программ, которые будут работать на всех компиляторах, которые придерживаются указанных нормативных соглашений, даже если они не будут работать со всеми компиляторами. Например. «Программа X строго соответствует требованиям при использовании с компиляторами, соответствующими нормативным стандартам целочисленной семантики типа 2, семантики указателя типа 3 и размера int 32 бита или больше». Увы, дела идут в обратном направлении; Авторы компиляторов мало заинтересованы в поддержке конструкций, которые работали бы в 99% компиляторов, написанных с 1989 по 2009 год.

supercat 13.08.2015 19:27

Другие вопросы по теме