【问题标题】:Bitwise shifting array of char'schar 的按位移位数组
【发布时间】:2012-04-28 21:19:33
【问题描述】:

我有一个字符数组,我试图将它们按位右移>>,然后& 与另一个数组一起移动。我想我对如何做到这一点有错误的想法。

我想,即使只是说明 my_array >>= 1 的字符数组也会改变所有内容,但我收到了一个错误:"error: invalid operands to binary >> (have ‘char[8]’ and ‘int’)"

我正在尝试做的按位比较是使用类似大小的数组启动到所有“0”...我得到:"error: invalid operands to binary & (have ‘char *’ and ‘char *’)"

我需要先将这些数组转换成别的东西,然后才能移动和比较?

对不起,我不是很清楚......到目前为止,所有的好建议,我想我越来越意识到没有超级简单的方法可以做到这一点。更具体地说,我要做的是将整个 char 数组的位向右移动 1,将右移的位添加到数组的最左侧,与另一个相同大小的数组进行按位比较。

从技术上讲,比较不必是数组与数组...我只需要这些位。在尝试进行移位/比较之前将数组转换为其他内容会更容易吗?

【问题讨论】:

  • 您是要旋转数组的内容,还是要按位移动数组的每个单独元素?这些操作在 C 中都不存在。您需要编写一个循环,将每个元素复制到一个位置,或者按位移动数组中的每个元素。

标签: c bit-manipulation


【解决方案1】:

你必须逐元素移动和比较。

for(i = 0; i < len; ++i)
    array[i] >>= 3;

例如。如果你想将移出一个元素的位移动到下一个元素,那就更复杂了,比如说你向右移动,那么

unsigned char bits1 = 0, bits2 = 0;
for(i = len-1; i >= 0; --i) {
    bits2 = array[i] & 0x07;
    array[i] >>= 3;
    array[i] |= bits1 << 5;
    bits1 = bits2;
}

在另一个方向遍历数组,因为您需要来自下一个更高插槽的位。

【讨论】:

    【解决方案2】:
    /** Shift an array right.
     * @param ar The array to shift.
     * @param size The number of array elements.
     * @param shift The number of bits to shift.
     */
    void shift_right(unsigned char *ar, int size, int shift)
    {
        int carry = 0;                              // Clear the initial carry bit.
        while (shift--) {                           // For each bit to shift ...
            for (int i = size - 1; i >= 0; --i) {   // For each element of the array from high to low ...
                int next = (ar[i] & 1) ? 0x80 : 0;  // ... if the low bit is set, set the carry bit.
                ar[i] = carry | (ar[i] >> 1);       // Shift the element one bit left and addthe old carry.
                carry = next;                       // Remember the old carry for next time.
            }   
        }
    }   
    

    【讨论】:

    • 这看起来很奇怪,或者我错过了一些东西。它看起来像是右移和左移的混合体。进位位旁边的注释说“将元素向左移动一位”,但它向右移动。而且for循环从高到低,我宁愿从低到高右移。
    • 我也会移动“int carry = 0;”在 for 循环之前的 while 循环内。
    • 这是非常低效的。如果要将数组移动 7 位,则数组中的每个 char 将被迭代 7 次。确实效率很低。
    【解决方案3】:

    您必须一一移动数组中的条目。 (如果您想比较其中两个,则需要逐个元素地进行比较。)

    如果您希望从每个字符移出的位会移入下一个字符,那么您也需要手动处理。

    如果您想要这种转移到下一个字节的行为,并且不介意让您的代码令人讨厌、不可移植和容易出错,您可以获取指向数组的指针,将其转换为像unsigned long long * 这样的东西,取消引用它并移动结果整数,然后再次存储它。

    但是,如果这是您想要的行为,那么您应该使用整数而不是 char[8] 开头。

    (如果您可以详细说明您的实际目标,那么可能会有更多有用的答案。)

    【讨论】:

      【解决方案4】:

      如果要对数组进行移位/OR/XOR/AND/等操作,应该循环执行,不能直接对数组执行。

      【讨论】:

        【解决方案5】:

        您只能移动该数组的成员,即 char(或 int)。你不能移动整个数组。移位my_array 尝试对数组类型(或指向 char 的指针)执行移位操作,这是不可能的。改为这样做:

        for (i = 0; i < size; i++) {
          my_array[i] >>= 1;
        }
        

        此外,您必须小心使用字符,因为它们通常是有符号的,并且包含负值的字符会从左边带上“1”而不是零。所以你最好使用无符号字符。

        编辑: 上面的代码很简单。如果您打算将整个数组右移,而不仅仅是每个字节,那么您需要“手动”将每个 LSB 复制到其右侧字节的 MSB。循环阅读 Richard Pennington 的答案。

        【讨论】:

        • 我假设他想将数组视为单个值,因此您也需要从更重要的字节中携带一点。
        【解决方案6】:
        /**
         * shift a number of bits to the right
         *
         * @param   SRC         the array to shift
         * @param   len         the length of the array
         * @param   shift       the number of consecutive bits to shift
         *
        */
        static void shift_bits_right(uint8_t SRC[], uint16_t len, uint32_t shift) {
            uint32_t i = 0;
        
            uint8_t start = shift / 8;
            uint8_t rest = shift % 8;
            uint8_t previous = 0;
        
            for(i = 0; i < len; i++) {
                if(start <= i) {
                    previous = SRC[i - start];
                }
                uint8_t value = (previous << (8 - rest)) | SRC[i + start] >> rest;
                SRC[i + start] = value;
            }
        }
        

        【讨论】:

          【解决方案7】:

          我知道这是个老话题,但我对可用的答案不满意,这是我最近写的东西,它允许您指定可以移动的位数,并且其中有简单的 XOR 加密。

          //https://github.com/ashvin-bhuttoo/CryptoTest/blob/master/CryptoTest/Crypto.cpp
          //CRYPTO CONFIGURATION PARAMETERS
          #define BIT_SHIFT 3
          #define XOR_KEY 0x3C
          #define ENABLE_XOR_VARIANCE true
          ////////////////////////////////
          
          int get_rs_mask(int shift)
          {
              switch (shift)
              {
              case 0:
                  return 0x00;
              case 1:
                  return 0x01;
              case 2:
                  return 0x03;
              case 3:
                  return 0x07;
              case 4:
                  return 0x0F;
              case 5:
                  return 0x1F;
              case 6:
                  return 0x3F;
              case 7:
                  return 0x7F;
              default:
                  throw "get_rs_mask -> Error, shift argument outside legal range 0-7";
              }
          }
          
          void shift_right(char* buf, int msg_len, int shift)
          {
              unsigned char tmp = 0x00, tmp2 = 0x00;
              for (int k = 0; k <= msg_len; k++)
              {
                  if (k == 0)
                  {
                      tmp = buf[k];
                      buf[k] >>= shift;
                  }
                  else
                  {
                      tmp2 = buf[k];
                      buf[k] >>= shift;
                      buf[k] |= ((tmp & get_rs_mask(shift)) << (8 - shift));
          
                      if (k != msg_len)
                          tmp = tmp2;
                  }
              }
          }
          
          int get_ls_mask(int shift)
          {
              switch (shift)
              {
              case 0:
                  return 0x00;
              case 1:
                  return 0x80;
              case 2:
                  return 0xC0;
              case 3:
                  return 0xE0;
              case 4:
                  return 0xF0;
              case 5:
                  return 0xF8;
              case 6:
                  return 0xFC;
              case 7:
                  return 0xFE;
              default:
                  throw "get_ls_mask -> Error, shift argument outside legal range 0-7";
              }
          }
          
          void shift_left(char* buf, int msg_len, int shift)
          {
              char tmp = 0x00, tmp2 = 0x00;
              for (int k = msg_len; k >= 0; k--)
              {
                  if (k == msg_len)
                  {
                      tmp = buf[k];
                      buf[k] <<= shift;
                  }
                  else
                  {
                      tmp2 = buf[k];
                      buf[k] <<= shift;
                      buf[k] |= ((tmp & get_ls_mask(shift)) >> (8 - shift));
          
                      tmp = tmp2;
                  }
              }
          }
          
          void crypt(char* buf, int msg_len, bool decrypt = false)
          {
              if (!decrypt)
              {
                  shift_right(buf, msg_len, BIT_SHIFT);
                  for (int k = 0; k < msg_len; k++)
                  {
                      buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
                  }
                  buf[msg_len] = '\0';
              }
              else
              {
                  for (int k = 0; k < msg_len; k++)
                  {
                      buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
                  }
                  shift_left(buf, (msg_len)-1, BIT_SHIFT);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-25
            • 2013-01-07
            • 2017-03-12
            • 2018-10-21
            • 1970-01-01
            相关资源
            最近更新 更多