Как круговой сдвиг массива из 4 символов?
У меня есть массив из четырех символов без знака. Я хочу рассматривать его как 32-битное число (предположим, что верхние разряды char меня не волнуют. Меня интересуют только младшие 8 бит). Затем я хочу кругово сдвинуть его на произвольное количество мест. У меня несколько разных размеров сдвига, все они определены во время компиляции.
например.
unsigned char a[4] = {0x81, 0x1, 0x1, 0x2};
circular_left_shift(a, 1);
/* a is now { 0x2, 0x2, 0x2, 0x5 } */
Изменить: всем, кто задается вопросом, почему я не упоминал CHAR_BIT!= 8, потому что это стандартный C. Я не указал платформу, так почему вы принимаете ее?
Ответы
Ответ 1
static void rotate_left(uint8_t *d, uint8_t *s, uint8_t bits)
{
const uint8_t octetshifts = bits / 8;
const uint8_t bitshift = bits % 8;
const uint8_t bitsleft = (8 - bitshift);
const uint8_t lm = (1 << bitshift) - 1;
const uint8_t um = ~lm;
int i;
for (i = 0; i < 4; i++)
{
d[(i + 4 - octetshifts) % 4] =
((s[i] << bitshift) & um) |
((s[(i + 1) % 4] >> bitsleft) & lm);
}
}
Очевидно,
Ответ 2
С учетом простой C лучший способ -
inline void circular_left_shift(char *chars, short shift) {
__int32 *dword = (__int32 *)chars;
*dword = (*dword << shift) | (*dword >> (32 - shift));
}
Uhmm, char
длится 16 бит, для меня это не ясно. Я предполагаю, что int
все еще 32 бит.
inline void circular_left_shift(char *chars, short shift) {
int i, part;
part = chars[0] >> (16 - shift);
for (i = 0; i < 3; ++i)
chars[i] = (chars[i] << shift) | (chars[i + 1] >> (16 - shift));
chars[3] = (chars[3] << shift) | part;
}
Или вы можете просто расслабиться в этом цикле.
Вы можете копать дальше в инструкцию asm ror
, на x86 она может выполнять такой сдвиг до 31 бит влево. Что-то вроде
MOV CL, 31
ROR EAX, CL
Ответ 3
Используйте union
:
typedef union chr_int{
unsigned int i;
unsigned char c[4];
};
Это безопаснее (из-за наложения указателя) и легче манипулировать.
EDIT: вы должны упомянуть ранее, что ваш char не 8 бит. Однако это должно сделать трюк:
#define ORIG_MASK 0x81010102
#define LS_CNT 1
unsigned char a[4] = {
((ORIG_MASK << LS_CNT ) | (ORIG_MASK >> (32 - LS_CNT))) & 0xff,
((ORIG_MASK << (LS_CNT + 8)) | (ORIG_MASK >> (24 - LS_CNT))) & 0xff,
((ORIG_MASK << LS_CNT + 16)) | (ORIG_MASK >> (16 - LS_CNT))) & 0xff,
((ORIG_MASK << (LS_CNT + 24)) | (ORIG_MASK >> ( 8 - LS_CNT))) & 0xff
};