Что это означает следующее утверждение C?((int *) & var) - PullRequest
0 голосов
/ 07 марта 2019

У меня есть следующий код на C для вычисления CRC16-USB для некоторых потоков данных:

uint16_t DRV_CANFDSPI_CalculateCRC16(uint8_t* data, uint16_t size)
{
    uint16_t init = CRCBASE;
    uint8_t index;

    while (size-- != 0) {
        index = ((uint8_t*) & init)[1] ^ *data++;
        init = (init << 8) ^ crc16_table[index];
    }

    return init;
}

Где crc16_table - это массив некоторых шестнадцатеричных значений в 2 байта (например, 0xAFF3), а data - это массив шестнадцатеричных значений в 1 байт (например, 0xA3), представляющих данные поток (полученный другими средствами). Размер - длина массива data .

Я хочу воспроизвести этот фрагмент кода на Python, но я не знаю, что означает это утверждение:

index = ((uint8_t*) & init)[1] ^ *data++;

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

Спасибо и хорошего дня!

Ответы [ 3 ]

1 голос
/ 08 марта 2019

init имеет тип uint16_t, поэтому выражение &init имеет тип "указатель на uint16_t" или uint16_t *. Выражение (uint8_t *) &init означает «получить адрес init, но рассматривать его как адрес uint8_t объекта, а не uint16_t объекта».

Этот адрес затем используется с оператором индекса - ((uint8_t *) &init)[1], что в основном эквивалентно "трактовать init как массив из двух uint8_t объектов и дать мне значение второго элемента в этом массиве" ,

Графический:

      +---+
init: |   | <-- ((uint8_t *) &init)[0]
      +---+
      |   | <-- ((uint8_t *) &init)[1]
      +---+

Таким образом, в основном, вы берете младшие 8 битов init, поразрядно XOR, что со значением текущего байта входного сообщения, и затем перемещаете data, чтобы указать на следующий байт ввода сообщение.

1 голос
/ 08 марта 2019

Я нашел решение для своей проблемы со следующим кодом:

def calculateCRC16(data):
    init = 0xFFFF
    for byte in data:
        index = (init >> 8) ^ byte
        init = ((init << 8) ^ crc16_table[index]) & 0xFFFF
    return init

Я думаю, что это довольно просто.Я проверил этот код с вышеупомянутым в C и результаты те же.Маскирование в Python переменной init необходимо, поскольку Python не ограничивает переменные int фиксированным размером в битах.Кроме того, в C для работы кода должен быть включен lib.

0 голосов
/ 08 марта 2019

Целью оператора index = ((uint8_t*) & init)[1] ^ *data++; является XOR старших восьми битов init со следующим байтом data (и для увеличения `данных).К сожалению, он написан неправильно.

В операторе index = ((uint8_t*) & init)[1] ^ *data++;:

  • & init принимает адрес init (который был определен с помощью uint16_t init = CRCBASE;).
  • (uint8_t*) преобразует этот адрес в указатель в uint8_t.Дальнейшее использование этого указателя требует, чтобы uint8_t был символьным типом в реализации C, что вероятно, но не гарантируется стандартом C.
  • Применение [1] к этому указателю извлекает следующий байт, кроме того, гдеуказатель указывает.Тот факт, что во второй строке используется init << 8, что приводит к значению, зависящему исключительно от * младших ** восьми бит init, говорит о том, что целью этой первой строки было получение старшего восемь битов init.

Однако стандарт C не требует, чтобы байты uint16_t были в каком-либо конкретном порядке, поэтому не гарантируется, что при использовании [1] будут полученыжелаемые биты.И это не нужно;использование init >> 8 вместо ((uint8_t*) & init)[1] даст требуемые биты.

Таким образом, код мог бы быть просто:

while (size--)
    init = init << 8 ^ crc16_table[init>>8 ^ *data++];
...