Функция C для Python (разные результаты)

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

Это версия кода C, которая работает:

int main(void)
{

uint8_t pac[] = {0x033,0x55,0x22,0x65,0x76};
uint8_t len = 5;
uint8_t chan = 0x64;

btLeWhiten(pac, len, chan);

    for(int i = 0;i<=len;i++)
    {
        printf("Whiten %02d \r\n",pac[i]);
     }

   while(1)
   {    

   }

  return 0;
  }



void btLeWhiten(uint8_t* data, uint8_t len, uint8_t whitenCoeff)
{

uint8_t  m;

while(len--){   
    for(m = 1; m; m <<= 1){

        if(whitenCoeff & 0x80){

            whitenCoeff ^= 0x11;
            (*data) ^= m;
        }
        whitenCoeff <<= 1;

    }
    data++;
  }
}

В настоящее время у меня есть в Python:

def whiten(data, len, whitenCoeff):
    idx = len 
    while(idx > 0):
        m = 0x01
        for i in range(0,8):
            if(whitenCoeff & 0x80):
                whitenCoeff ^= 0x11
                data[len - idx -1 ] ^= m
                whitenCoeff <<= 1 
                m  <<= 0x01

        idx = idx - 1


pac = [0x33,0x55,0x22,0x65,0x76]
len = 5
chan = 0x64

def main():

whiten(pac,5,chan)
print pac


if __name__=="__main__":
    main()

Проблема, которую я вижу, состоит в том, что whitenCoeff всегда остается 8 бит в фрагменте C, но он становится больше, чем 8 бит в Python на каждом проходе цикла.

5 ответов

В C вы пишете данные от 0 до len-1, но в Python вы пишете данные от -1 до len-2. Удалите -1 из этой строки:

data[len - idx -1 ] ^= m

как это

data[len - idx] ^= m

Вы также должны поместить эту строку вне if:

whitenCoeff <<= 1 

У вас есть еще несколько проблем.

  1. whitenCoeff <<= 1; находится за пределами if блок в вашем коде C, но это внутри if блок в вашем коде Python.
  2. data[len - idx -1 ] ^= m не был правильно переведен, он работает в обратном направлении от кода C.

Этот код производит тот же вывод, что и ваш код на C:

def whiten(data, whitenCoeff):
    for index in range(len(data)):
        for i in range(8):
            if (whitenCoeff & 0x80):
                whitenCoeff ^= 0x11
                data[index] ^= (1 << i)

            whitenCoeff = (whitenCoeff << 1) & 0xff

    return data

if __name__=="__main__":
    print whiten([0x33,0x55,0x22,0x65,0x76], 0x64)

whitenCoeff <<= 1 через некоторое время C становится 0, потому что это 8-битные данные.

В python такого ограничения нет, поэтому вы должны написать:

whitenCoeff = (whitenCoeff<<1) & 0xFF

маскировать старшие биты.

(не забудьте проверить замечание vz0 о границе массива)

плюс была проблема с отступом.

переписанный код, который дает тот же результат:

def whiten(data, whitenCoeff):
    idx = len(data)
    while(idx > 0):
        m = 0x01
        for i in range(0,8):
            if(whitenCoeff & 0x80):
                whitenCoeff ^= 0x11
                data[-idx] ^= m
            whitenCoeff = (whitenCoeff<<1) & 0xFF
            m  <<= 0x01

        idx = idx - 1


pac = [0x33,0x55,0x22,0x65,0x76]
chan = 0x64

def main():

    whiten(pac,chan)
    print(pac)


if __name__=="__main__":
    main()

Немного не по теме: обратите внимание, что версия C уже имеет проблемы:

for(int i = 0;i<=len;i++)

должно быть

for(int i = 0;i<len;i++)

Я решил это, добавив код Python с 0xFF. Это удерживает переменную от превышения 8 бит.

Ваш код в C не работает должным образом, поскольку отображает еще одно значение, чем доступно в pac, Исправление для этого должно привести к отображению 5 значений вместо 6 значений. Чтобы скопировать логику из C к Pythonв попытке дублировать результаты было написано следующее:

#! /usr/bin/env python3
def main():
    pac = bytearray(b'\x33\x55\x22\x65\x76')
    chan = 0x64
    bt_le_whiten(pac, chan)
    print('\n'.join(map('Whiten {:02}'.format, pac)))


def bt_le_whiten(data, whiten_coeff):
    for offset in range(len(data)):
        m = 1
        while m & 0xFF:
            if whiten_coeff & 0x80:
                whiten_coeff ^= 0x11
                data[offset] ^= m
            whiten_coeff <<= 1
            whiten_coeff &= 0xFF
            m <<= 1


if __name__ == '__main__':
    main()

Для имитации 8-битных целых чисел без знака, фрагмент & 0xFF используется в нескольких местах, чтобы обрезать числа до нужного размера. bytearray тип данных используется для хранения pac так как это представляется наиболее подходящим способом хранения в этом случае. Код все еще нуждается в документации, чтобы правильно понять это.

Другие вопросы по тегам