C - 使用位移运算符进行基本转换

时间:2014-01-02 13:34:47

标签: c bit-manipulation shift

我正在尝试将一些数据从十六进制转换为C中的base64,我在网上找到了一个算法,但我真的想知道它是如何工作的,而不仅仅是实现它并将其解雇。如果有人可以解释以下是如何工作的,我将不胜感激。我一直在阅读关于移位操作符的内容,我似乎并不像我想的那样理解它们...它不是很适合我。

for (x = 0; x < dataLength; x += 3) 
{
  /* these three 8-bit (ASCII) characters become one 24-bit number */
  n = data[x] << 16;

  if((x+1) < dataLength)
     n += data[x+1] << 8;

  if((x+2) < dataLength)
     n += data[x+2];

  /* this 24-bit number gets separated into four 6-bit numbers */
  n0 = (uint8_t)(n >> 18) & 63;
  n1 = (uint8_t)(n >> 12) & 63;
  n2 = (uint8_t)(n >> 6) & 63;
  n3 = (uint8_t)n & 63;

此代码取自Wikibooks,它不是我的,我只是想了解位移以及它如何允许我转换数据。

感谢您的帮助,我真的很感激。

来源:Base64

2 个答案:

答案 0 :(得分:5)

首先,输入数据不是十六进制,如你所说。它只是存储为字节的数据。代码将为您提供base64表示(尽管您发布的代码缺少将n0n1n2n3映射到可打印ASCII字符的部分

假设输入的前三个字节是(以二进制表示,每个字母代表0或1):

abcdefgh, ijklmnop, qrstuvwx

代码的第一部分将它们组合成一个24位数字。这是通过将第一个16位向左移位而第二个向左移动8位并添加:

来完成的
  abcdefgh0000000000000000      (abcdefgh << 16)
+ 00000000ijklmnop00000000      (ijklmnop << 8)
  0000000000000000qrstuvwx
  ------------------------
  abcdefghijklmnopqrstuvwx

然后通过移位和移动将其分成四个6位数。例如,通过向右移动12位并且用111111

来计算第二数字
n     =   abcdefghijklmnopqrstuvwx

n>>12 =   000000000000abcdefghijkl
63    =   000000000000000000111111

And'ing gives:
          000000000000000000ghijkl

答案 1 :(得分:2)

好的,这里有一点解释..

data [x]是一个字符数组,一个字符是usbit 8bits ..(随机8位数01010101) n是一个32位数,这里是一个随机的32位数(01011111000011110000111100001111),认为那里有32位:)

记住n是32位,数据只有8位..让我们通过第一行

 n = data[x] << 16;

&lt;&lt; 16优先于等号,因此首先评估它。

data [x]&lt;&lt; 16表示将数据[x]中的位移动到左侧16位。 假设data [x] ='a'这在内存中由01100001表示(1个字节),所以让我们向左移动16位

n = 00000000 01100001 00000000 00000000

接下来我们有

if((x+1) < dataLength)
 n += data[x+1] << 8;

这表示将下一个字符数据[x + 1]移动8位并将其添加到n;所以我们先把它移动8位

( I assumed it was 'a' again)
00000000 00000000 01100001 00000000 
(this is done in some register in your processor)

现在可以将它添加到n

00000000 01100001 01100001 00000000

下一部分是

 if((x+2) < dataLength)
 n += data[x+2];

让我们在这里做同样的事情,注意没有位移,因为n的最后8位是免费的!我们需要做的就是将它添加到n

b = 01100010(假设数据[x + 2] ='b')     将其添加到n

  00000000 01100001 01100001 01100010

太好了,现在我们有一个24位数(实际上n是32位,但最后24位是我们需要的)

下一部分

n0 = (uint8_t)(n >> 18) & 63; 
(take note n0 is only 8bits wide or a single unsigned byte)

take n and move it to the left by 18bits and "and" it with 63

n = 00000000 01100001 01100001 01100010
n moved 18bits to right is  00000000 00000000 00000000 00011000

now n is cast to an unsigned int of 8bits (uint8_t)

so now it becomes 00011000

last part is the & operator(bitwise and) 

    00011000 & 
    00111111
n0= 00011000 

现在重复此操作