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

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

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

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


person Paweł Hajdan    schedule 29.09.2008    source источник


Ответы (3)


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

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

person moonshadow    schedule 29.09.2008
comment
Загвоздка со сдвигом битов в том, что в C/C++ поведение не определено для отрицательных чисел. - person Alexander; 29.09.2008
comment
Для отрицательного значения оно не неопределенно, оно определяется реализацией. Для отрицательного x это не определено, но здесь этого никогда не происходит. И формат хранения отрицательного целого числа тоже определяется реализацией (в пределах определенных возможностей), так что в этом отношении это не хуже, чем использование объединения. - person Steve Jessop; 29.09.2008
comment
Меня не волнует, расширяет ли значение знак сдвига, я маскирую все, кроме нижних шестнадцати битов. Они хорошо определены. - person moonshadow; 29.09.2008
comment
Я думаю, что Александр указывает, что результатом сдвига вправо отрицательной величины со знаком не обязательно должно быть ни 0-заполнение, ни знак-заполнение. Это может быть что угодно, лишь бы компилятор документировал, что именно. По крайней мере на С++. Я тоже не проверял стандарт C. Однако почти на всех компиляторах вы правы. - person Steve Jessop; 29.09.2008
comment
Вы меня поняли: правильная формулировка из стандарта определяется реализацией. Я думаю, что самое простое решение для решения в этом ответе - сначала преобразовать значение в беззнаковые типы. Тогда это решение превосходит структуры, поскольку дает одинаковые результаты для архитектур с прямым порядком байтов и обратным порядком байтов. - person Alexander; 29.09.2008
comment
определение реализации означает, что компилятор C++ в принципе может генерировать код, который, скажем, ничего не делает, если левая часть оператора сдвига вправо отрицательна. - person Alexander; 29.09.2008
comment
Это позаботится, по крайней мере, о проблеме с прямым/обратным порядком байтов в ответах, основанных на союзе. - person slashmais; 29.09.2008
comment
Я понимаю, что на самом деле в большинстве компиляторов сдвиг вправо либо заполняет левые биты 0, либо распространяет знак, но лучше перестраховаться, сначала преобразовав значение в беззнаковое. - person Alexander; 29.09.2008
comment
Да, я бы тоже так сделал - преобразование со знаком -> без знака определено (по крайней мере, в C++, я еще не проверял C). Таким образом, результат везде одинаков, при условии, что типы имеют ожидаемые значения MIN/MAX. - person Steve Jessop; 29.09.2008
comment
Отредактировано, тогда, для чего это стоит. Хотя я никогда не сталкивался с реализацией, которая делала бы что-то кроме расширения знака, я думаю, что лучше быть в безопасности. - person moonshadow; 29.09.2008
comment
@SteveJessop: Интересно, есть ли какая-то особая причина, по которой правила Стандарта для смещения вправо отрицательных чисел или приведения больших значений к знаковым типам меньшего размера не определяют никаких поведенческих требований? Из того, что я могу сказать, для реализации было бы совершенно законным указать, что для всех отрицательных x x>>y даст 42, или даст y, или вычислит число любым способом без побочных эффектов, который нравится автору реализации, что делает x>>y с отрицательным x по сути бесполезен в строго соответствующем коде, даже если такой код был бы одинаково счастлив с... - person supercat; 12.08.2015
comment
... любые средства оценки, которые может правдоподобно использовать любая удаленно-нормальная реализация. - person supercat; 12.08.2015
comment
@supercat: Я полагаю, это потому, что они не хотели предотвращать реализации, просто используя код операции сдвига архитектуры, и по какой-то причине не были уверены, что смогут предоставить список параметров, который будет включать все удаленно нормальные текущие и будущие архитектуры. Текущая ситуация такова, что эти строго соответствующие программы должны перед сдвигом проверять, является ли целое число отрицательным, если только программист не знает, что оно неотрицательно. В любой архитектуре, где код операции сдвига не обеспечивает соответствующего поведения, компилятор должен будет выдать код для проверки всех сдвигов. - person Steve Jessop; 13.08.2015
comment
@SteveJessop: имеет смысл, чтобы поведение определялось реализацией для архитектур с дополнением или величиной знака, поскольку есть преимущества в том, что реализация действует на представление числа, но также есть преимущества в вычислении того же значения, что и архитектура с дополнением до двух, когда это возможно (приведение uint к int к uint в соответствии с такими правилами будет выполнять циклический обход всех значений, кроме UINT_MAX/2, а подписанный сдвиг вправо будет предлагать семантику деления на полу, которая отличается от семантики подписанного разделение способами, которые часто бывают полезными). Могут быть и такие случаи... - person supercat; 13.08.2015
comment
... где альтернативные вычисления могут быть полезны в реализации, которая использует математику с дополнением до двух, но имеет различное заполнение для чисел со знаком и без знака. Однако для реализации, использующей целые числа с дополнением до двух без заполнения, единственным правдоподобным вариантом, который я мог себе представить в аппаратном обеспечении, было бы отсутствие расширяющегося со знаком сдвига вправо (и я видел подобное аппаратное обеспечение), и даже если знак -расширение сдвига вправо требует больше кода, чем смещение без знака, я бы посчитал x = (int)((unsigned)x>>1) не менее понятным, чем x>>1 в случае, когда... - person supercat; 13.08.2015
comment
... семантика заполнения нулями была уместной. Я согласен с тем, что в настоящее время написан Стандарт, код, который хочет выполнить сдвиг вправо с расширенным знаком, должен пройти через некоторые обручи, чтобы выполнить это. Мой вопрос заключается в том, служит ли какой-либо полезной цели то, что Стандарт написан таким образом. На мой взгляд, если более 90% компиляторов позволяют записывать операции более понятным способом (и на некоторых компиляторах, вероятно, также будут выполняться более эффективно), чем любой строго соответствующий способ их написания, Стандарт должен признать что в качестве нормативного определите макрос, указывающий... - person supercat; 13.08.2015
comment
... независимо от того, придерживается ли компилятор этого соглашения, и определите термины, связанные с соответствием, для программ, которые будут работать на всех компиляторах, которые придерживаются указанных нормативных соглашений, даже если они не будут работать на всех компиляторах. Например. Программа X строго совместима при использовании с компиляторами, отвечающими нормативным стандартам для целочисленной семантики типа 2, семантики указателя типа 3 и размера int 32 бита или больше. Увы, дела идут в обратном направлении; Авторы компиляторов мало заинтересованы в поддержке конструкций, которые работали бы на 99% компиляторов, написанных с 1989 по 2009 год. - person supercat; 13.08.2015

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

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

person workmad3    schedule 29.09.2008
comment
Можете ли вы гарантировать, что в структуре не будет отступов между короткими целыми числами? - person Alexander; 29.09.2008
comment
Ой, изначально я писал о трех беззнаковых целых числах. Это, вероятно, вводит вас в заблуждение. Простите за это. В любом случае ваш ответ был полезен. - person Paweł Hajdan; 29.09.2008
comment
Первоначально это был ‹code›unsigned short int‹/code› (вероятно, по 2 байта каждый — это нормально). Я хотел сказать, что если вы не уверены в правилах заполнения/выравнивания, эта структура опасна. - person Alexander; 29.09.2008

person    schedule
comment
Повлияет ли это на Little/Big-endian? - person slashmais; 29.09.2008
comment
Да, вы получаете разные результаты для систем с обратным порядком байтов и для систем с прямым порядком байтов. - person Chris Jester-Young; 29.09.2008
comment
Это определенно быстрое решение в том же порядке, что и: @numbers = unpack 'S4', pack 'Q', $number; в Перле - person Chris Jester-Young; 29.09.2008
comment
Потерпит неудачу, например, Cray и TI DSP, и это лишь несколько процессоров, где Short может быть 32-битным. - person MSalters; 29.09.2008
comment
Я на 100% согласен, что это решение вообще не портабельно. Возможно, мне следует изменить ответ, чтобы использовать inttypes.h. :-) - person Chris Jester-Young; 29.09.2008