unsigned long long int 的按位运算超过 32 位时不适用

Bitwise operation for unsigned long long int is not applied when it's over 32bits

我只是在 Mac OS X 上做一些测试。但我不明白为什么会这样。

当我尝试对 unsigned long long int 应用一些按位运算时, 当某些操作超过32位时,没有关于该操作的设备。

代码如下..

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


#define KEY_MAX             31
#define INDEX_MASK          0b11111


unsigned long long int makePlain(unsigned long long int chipherText, int pattern);


static char testArray[] = {
    'A', 'B', 'C', 'D', 'E',
    'F', 'G', 'H', 'I', 'J',
    'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T',
    'U', 'V', 'W', 'X', 'Y',
    'Z', ' ', '@', '@', '@' };


int main(void) {
    unsigned int i;
    unsigned long long int chipherText = 0b1010100100101010101111001000110101110101001001100111010;
    unsigned long long int plain = 0;

    for (i = 2; i <  3; i++) {
        plain = makePlain(chipherText, i);
        int j;
        for (j = 0; j < 11; j++) {
            printf("IDX=[%d] : %d\n", j,(unsigned int)(plain >> (5 * j) & INDEX_MASK));
        }

        printf("%c%c%c%c%c%c%c%c%c%c%c\n",
                testArray[(unsigned int)((plain >> (5 * 10)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 9)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 8)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 7)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 6)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 5)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 4)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 3)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 2)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 1)) & INDEX_MASK)],
                testArray[(unsigned int)((plain >> (5 * 0)) & INDEX_MASK)] );
    }

    return 0; }


unsigned long long int makePlain(unsigned long long int chipherText, int pattern) {
    int i;
    unsigned int temp;
    unsigned long long int plain = 0;

    for (i = 0; i < 11; i++) {
        temp = ((chipherText >> (5 * i)) & INDEX_MASK);
        temp = temp ^ pattern;
        printf("[%d]:temp -after xor : %d\n", i, temp);
        plain |= (temp << (5 * i)); // Here is make problems.
    }

    return plain; }

(一开始,代码不好看..对不起大家。)

请查看 makePlain 函数的最后一行循环..

当变量i为6时,写位超过32位。 在那之后,"plain |="的所有操作都不适用,但对于超过 32 位的位仍然为 0。

下面是 Xcode 调试器结果。

所以,我只是确认了 asm,然后我找到了那种代码..

      call    printf
  LM42:
      movl    -4(%rbp), %edx          # i -> edx
      movl    %edx, %eax              # eax = i
      sall    , %eax                # i * 4
      addl    %edx, %eax              # i * 5
      movl    -20(%rbp), %edx         # temp -> edx (maybe problem
                                      # becase it load 64bit on 32)
      movl    %eax, %ecx              # eax -> ecx ==> ecx = i * 5
      sall    %cl, %edx               # edx << i * 5 //why 32 bit? 
      movl    %edx, %eax              # eax saving (plain) //why 32bit
      movl    %eax, %eax              # 
      orq>%rax, -16(%rbp)             # saving

我认为上面的代码是

plain |= (temp << (5 * i));

关于 makePlain 函数。

我的问题是..

您的 temp 变量只有 32 位,因为它是一个 unsigned int。将其类型更改为 unsigned long long 以解决您的问题。

会发生什么?

这一行:

plain |= (temp << (5 * i));

变量 temp 具有 unsigned int 类型,通常是 32 位类型。因此,左移也是一个 32 位的移位,任何超出 32 位的都将被丢弃。当 i 大于 6 时,代码也表现出未定义的行为,因为将值移动比其类型更多的位是未定义的。

有两种方法可以解决这个问题。一种是给 temp 正确的类型,另一种是使用适当的转换来确保转换是 unsigned long long 转换:

plain |= ((unsigned long long)temp << (5 * i));

在编写代码时,请始终确保所有相互依赖的变量都应采用相同的数据类型。它避免了这种情况下的内存溢出