2010-10-12 34 views
10

我有一个四个无符号字符的数组。我想把它看作一个32位的数字(假设char的高位不关心,我只关心低8位)。然后,我想循环转移它的任意数量的地方。我有几个不同的换档尺寸,都是在编译时确定的。如何循环移位4个字符的数组?

E.g.

unsigned char a[4] = {0x81, 0x1, 0x1, 0x2}; 
circular_left_shift(a, 1); 
/* a is now { 0x2, 0x2, 0x2, 0x5 } */ 

编辑:!为了大家想知道我为什么没有提到CHAR_BIT = 8,因为这是标准C.我没有指定一个平台,让你为什么假设一个?

+2

为什么不将其存储在32位数据如int(取决于机器和所有)? – JoshD 2010-10-12 19:23:08

+0

如果字符是16位那么你的例子是错误的,基本上你想要把它们当作8位字符,对吧? – 2010-10-12 21:05:23

回答

5
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); 
    } 
} 

显然

+1

这看起来很有希望,让我跑几个测试用例。它比我的第一次尝试更干净。 – 2010-10-12 20:01:42

+2

我看到你已经假设小端,但它可以很容易地修改为大端。 – 2010-10-12 20:02:20

1

同时牢记纯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 
+2

我会这样做,但CHAR_BIT是16,因此在无符号字符[4]上面使用32位字进行别名不起作用。我不能依赖非标准的C功能,但感谢您的回应。 – 2010-10-12 19:33:09

+0

刚刚修好。目标机器是什么? – Keynslug 2010-10-12 19:54:48

+1

适用于TI DSP,其中int!= 32位,但我没有看到代码中的哪个位置无关紧要。这是否限制为<= 7? – 2010-10-12 20:04:01

-1

使用union

typedef union chr_int{ 
    unsigned int i; 
    unsigned char c[4]; 
}; 

它的安全(因为指针别名),并更容易操纵。

编辑:你应该早些提到你的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 
}; 
+1

+1使用'unsigned int',它实际上与问题中的测试数据一起使用。这与平台上的排序无关吗? – 2010-10-12 19:32:30

+2

请参阅我对之前答案的评论。 – 2010-10-12 19:33:57

+0

我看到你的编辑只是一个数组..我错过了什么? – 2010-10-12 20:04:50