C - побитовая конкатенация, приводящая к отсутствию информации - PullRequest
0 голосов
/ 01 октября 2018

У меня есть пять переменных короткого типа, которые я хочу объединить в 32-битный тип unsigned int.Мне нужно объединить пять коротких переменных.Имена этих переменных называются кодом операции (5 бит), reg1 (4 бита), reg2 (4 бита), reg3 (4 бита), расширением (3 бита) и addr_constant (12 бит).Теперь мой код не работает для одного случая, который я не знаю почему.Я перечислил мой код ниже.

Цель этого кода - преобразовать определенные значения в 32-битную машинную инструкцию, что означает, что, хотя я получил эквивалентное значение, мне все равно нужно иметь 32-битную инструкцию.

...
unsigned int *const word;
unsigned short opcode = 1;
unsigned short reg1 = 3; 
unsigned short reg2 = 4;
unsigned short reg3 = 5;
unsigned short extension = 0;
unsigned int addr_constant = 0;

unsigned int machine_word = 0;
machine_word = machine_word | (opcode << 27);
machine_word = machine_word | (reg1 << 23);
machine_word = machine_word | (reg2 << 19);
machine_word = machine_word | (reg3 << 15);

machine_word = machine_word | (extension << 12);
machine_word = machine_word | addr_constant;

*word = machine_word
return 0;
...

Вывод в двоичном виде должен быть:

0000 1001 1010 0010 1000 0000 0000 0000.

Но сейчас это:

1001 1010 0010 1000 0000 0000 0000. 

Как видите, он пропускает первые 4нули.

В следующем тесте «слово»: unsigned int * const word.И в конце кода выше я написал «* word = machine_word».В тесте он сравнивает: "word == 0x09a28000" Я не прошел следующий тест.

assert(word == 0x09a28000);

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Может быть, проблема только в интерпретации результата.Я запустил следующий код, который основан на алгоритме, который вы предоставили с некоторыми изменениями в логических операциях и печати результатов.Основная логика операции остается неизменной по сравнению с тем, что вы опубликовали, поэтому, возможно, результат неверно истолкован.

Код следующий:

#include <stdio.h>

int main() {
    int i, j, mask;

    unsigned short opcode = 1;
    unsigned short reg1 = 3; 
    unsigned short reg2 = 4;
    unsigned short reg3 = 5;
    unsigned short extension = 0;
    unsigned int addr_constant = 0;

    unsigned int machine_word = 0;
    machine_word |= opcode << 27;
    machine_word |= reg1 << 23;
    machine_word |= reg2 << 19;
    machine_word |= reg3 << 15;

    machine_word |= extension << 12;
    machine_word |= addr_constant;

    for (i = 7; i >= 0; i--) {
        for (j = 3; j >= 0; j--){
            printf("%d", (machine_word & 0x00000001 << (4 * i + j)) >> (4 * i + j));
        }
        printf(" ");
    }
    printf("\n");
    return 0;
}

Код дает следующий вывод:

0000 1001 1010 0010 1000 0000 0000 0000

Это должен быть результат, который вы ищете, он соответствует целому значению без знака 161644544 (0x9A28000).

0 голосов
/ 01 октября 2018

Просто используйте битовые поля - они предназначены для этого.

struct all_the_things {
  unsigned opcode : 5;
  unsigned reg1 : 4;
  unsigned reg2 : 4;
  unsigned reg3 : 4;
  unsigned extension : 3;
  unsigned addr_constant : 12;
};

После того, как вы заполнили такую ​​структуру, вы можете преобразовать ее в 32-битное целое число следующим образом:

uint32_t num;
memcpy(&num, &things, 4);

(Не беспокойтесь, оптимизирующий компилятор не будет вызывать функцию для копирования 4 байтов.)

...