在C中提取最后N位的位掩码和按位操作

hmae6n7t  于 2023-03-22  发布在  其他
关注(0)|答案(4)|浏览(155)

我在C代码中遇到了一个小问题
本质上,我正在阅读一个二进制文件,并提取了指令,每条指令的长度为4字节,每条指令的大小为32位。
我有一个程序计数器,它从0开始,在地址1024结束,每次读取4个字节
所以

  • 指令0 =程序计数器@0,
  • 指令1 =程序计数器@4

现在这不是问题了,我的代码正确地阅读了文件的内容

问题是:

我希望存储返回一个指针到最后7位的指令
所以如果我有指令@程序计数器0 =
01111111111100000000000100010011
以下哪种等效十六进制表示形式为:

unsigned char instruction[INSTRUCTION_SIZE] = { 0x7F, 0xF0, 0x01, 0x13 };

其中INSTRUCTION SIZE4,因为每个指令是4字节,因此32位长。
我希望返回一个包含最后7位的变量,在我们的例子中是0010011
现在,我有一个简单的函数,可以打印最后7位

void print_first_instruction(unsigned char *instruction) {
    unsigned char value = instruction[0];
    unsigned char last_seven_bits = value & instruction[0];

    char bit0 = 0x00;
    printf("\nLast 7 bits in binary: ");
    for (int i = 6; i >= 0; i--) {
        bit0 |= (last_seven_bits >> i) & 0x01; // shift the bits and use bitwise OR to assign the bits to bit0
        bit0 <<= 1; // shift bit0 to the left to make space for the next bit
        printf("%d", (last_seven_bits >> i) & 0x01);

        if (bit0 == 0x13) {
            printf("Add command");
        }
    }
}

int main(int argc, char *argv[]) {
    FILE *file;
    char *filename = "print.mi";
    int i, j;
    long filesize;

    file = fopen(filename, "rb");
    if (file == NULL) {
        printf("Error: could not open file.\n");
        return 1;
    }

    fseek(file, 0L, SEEK_END);
    filesize = ftell(file);
    rewind(file);

    // read the file and store its contents in instruction_memory
    for (i = 0; i < filesize; i += INSTRUCTION_SIZE) {
        fread(&blob.instruction_memory[i], 1, INSTRUCTION_SIZE, file);
    }
    for (program_counter = 0; program_counter < INSTR_MEM_SIZE; program_counter += INSTRUCTION_SIZE) {
        unsigned char instruction[INSTRUCTION_SIZE];
        for (int j = INSTRUCTION_SIZE - 1; j >= 0; j--) {
            instruction[j] = blob.instruction_memory[program_counter + j];
        }
        print_first_instruction(instruction);
    }
    fclose(file);
    return 0;
}

此代码打印第一条指令的最后7位
第一条指令是01111111111100000000000100010011
因此,它提取0010011
现在,我希望编写一些代码来检查最后一位是否等于0010011
在这种情况下,它显然是,所以我想打印到标准输出(“添加操作”)已被发现
我该怎么做。
因此,我还想存储最后7位,以防我希望函数使用除第一个指令以外的其他指令

kiayqfof

kiayqfof1#

32位指令似乎是以大端格式存储在内存中的,即:最高有效字节在前,最低有效字节在后。对于这种字节排序,要提取最低有效的7位,您可以只屏蔽第4个字节的低7位:

bits = instruction[3] & 0x7F;

请注意,当今大多数台式机和笔记本电脑中的字节顺序都是小端,因此为了将文件内容转换为32位指令,需要特定的代码:

#include <stdint.h>

uint32_t get_opcode(unsigned char instruction[4]) {
    return ((uint32_t)instruction[0] << 24) |
           ((uint32_t)instruction[1] << 16) |
           ((uint32_t)instruction[2] <<  8) |
           ((uint32_t)instruction[3] <<  0);
}

幸运的是,上面的代码在大多数平台上只编译为1或2条指令。

1tu0hz3e

1tu0hz3e2#

你不需要一位一位地移位。下面你有一个函数的例子,它根据endianess(字节顺序)转换为uint32_t并从中提取n位。

uint32_t extractLastBits(const uint32_t val, int nbits)
{
    uint32_t mask = ((1ULL << nbits) - 1);
    return val & mask;
}

uint32_t touint32(const void *ptr, const size_t offset, int reverse)
{
    const unsigned char *cptr = ptr;
    uint32_t result;

    if(!reverse) memcpy(&result, cptr + offset, sizeof(result));
    else result = (uint32_t)cptr[0] << 24 | 
                  (uint32_t)cptr[1] << 16 | 
                  (uint32_t)cptr[2] << 8 | 
                  (uint32_t)cptr[3] << 0;
    return result;
}

int main(void)
{
    //little indian
    char arr[] = {0x13, 0x01, 0xf0, 0x7f};
    printf("0x%"PRIx32"\n", extractLastBits(touint32(arr, 0, 0), 7));

    //big endian
   unsigned char instruction[] = { 0x7F, 0xF0, 0x01, 0x13 };
    printf("0x%"PRIx32"\n", extractLastBits(touint32(instruction, 0, 1), 7));

}

https://godbolt.org/z/n4xhhrKfG

xxe27gdn

xxe27gdn3#

  • 移位应该发生在 * 添加一个位之前。否则,将向值添加额外的空间,最终值将存储为0x26(加倍)而不是0x13
  • 与所需值0x13的比较应发生在 * 循环后 * 以提取位,而不是在每次迭代中。
void print_first_instruction(unsigned char* instruction) {
        unsigned char value = instruction[0];
        unsigned char last_seven_bits = value & instruction[0];
    
        char bit0 = 0x00;
        printf("\nLast 7 bits in binary: ");
        for (int i = 6; i >= 0; i--) {
            bit0 <<= 1; // shift bit0 to the left to make space for the next bit
            bit0 |= (last_seven_bits >> i) & 0x01; // shift the bits and use bitwise OR to assign the bits to bit0
            printf("%d", (last_seven_bits >> i) & 0x01)
        }
    
        if(bit0 == 0x13){
            printf("Add command");
        }
    }
qoefvg9y

qoefvg9y4#

要从包含4个元素的字符数组(或子数组)的最后一个元素中提取最后7位,您应该使用掩码0x7F
因此,一个返回4个元素的字符数组的最后一个元素的7位的函数可以如下所示

unsigned char extract_last_7_bits( const unsigned char *value )
{
    return  *( value + 3 ) & 0x7F;
}

如果需要,可以将返回类型从unsigned char更改为int
在函数的调用者中,你可以写例如

if ( extract_last_7_bits( instruction ) == 0x13 )
{
    puts( "Add command" );
}

相关问题