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

Заголовок C: (header.h) (не мой. См. PGPFormat)

#define CRC24_INIT 0xB704CEL
#define CRC24_POLY 0x1864CFBL

long crc_octets_1(unsigned char *octets, long len)
{
    long crc = CRC24_INIT;
    int i;
    while (len) {
        crc ^= (*octets++) << 16;
        for (i = 0; i < 8; i++) {
            crc <<= 1;
            if (crc & 0x1000000)
                crc ^= CRC24_POLY;
        }
        len-=1;
    }
    return crc & 0xFFFFFFL;
}

Моя быстрая альтернатива:

let CRC24_INIT_: Int = 0xB704CE
let CRC24_POLY_: Int = 0x1864CFB

func crc_octets_1( _ octets: UnsafeMutablePointer<UInt8>, _ len: Int) -> Int {
    var octets2 = octets
    var crc = CRC24_INIT;
    var l=len
    while (l != 0) {
        octets2 += 1 //i have also tried incrementing the actual value that is being pointed to. It still doesn't work. I have also tried urinary 
        crc ^= Int(octets2.pointee) << 16;
        for _ in 0..<8 {
            crc <<= 1;
            if ((crc & 0x1000000) != 0) {
                    crc ^= CRC24_POLY;
            }
        }
        l -= 1
    }
    return crc & 0xFFFFFF;
}

Финальный тест

func test() {
    var dataBytes: [UInt8] = [1,2,3,4,5]

    let checksum1 = crc_octets_1(&dataBytes, dataBytes.count)
    let checksum2 = crc_octets_2(&dataBytes, dataBytes.count)
    
    XCTAssertEqual(checksum1, checksum2)
}

Вот что я получаю взамен: XCTAssertEqual failed: ("3153197") is not equal to ("1890961")

1
Evergreen 10 Янв 2022 в 06:17
2
Что ты делаешь с octets2 += 1? Код, который вы заменяете, выполняет ^= с текущим значением, а затем увеличивает значение (x++). Кажется, вы сначала увеличиваете значение, а затем работаете с ним (++x). Нет причин для octets2. Чтобы отладить это, запустите исходный код и распечатайте *octets и crc на каждой итерации. Затем сравнивайте это с вашим новым кодом на каждой итерации. В первый раз они не равны, это ваша ошибка. (Это будет первая итерация.)
 – 
Rob Napier
10 Янв 2022 в 06:43
3
Вы спаситель. Спасибо! Это сработало, когда я поменял местами octets2 += 1 и crc ^= Int(octets2.pointee) << 16;
 – 
Evergreen
10 Янв 2022 в 06:50

1 ответ

Лучший ответ

Как указал Роб Нэпьер, проблема заключается в том, где вы увеличиваете octets2. Objective-C увеличивает указатель после получения значения, а версия Swift увеличивает его раньше.

Но я мог бы пойти еще дальше и полностью исключить небезопасные указатели (octets и octets2), а также переменные len и l. Вместо этого просто передайте массив dataBytes напрямую:

func crc(for bytes: [UInt8]) -> Int {
    var crc = CRC24_INIT
    for byte in bytes {
        crc ^= Int(byte) << 16
        for _ in 0..<8 {
            crc <<= 1
            if (crc & 0x1000000) != 0 {
                crc ^= CRC24_POLY
            }
        }
    }
    return crc & 0xFFFFFF
}

Или, если вы хотите пофантазировать, вы можете вместо этого сделать общее представление, которое будет принимать любые Sequence из UInt8 (т. е. либо массив [UInt8], либо Data):

func crc<T>(for bytes: T) -> Int where T: Sequence, T.Element == UInt8 {
    var crc = CRC24_INIT
    for byte in bytes {
        crc ^= Int(byte) << 16
        for _ in 0..<8 {
            crc <<= 1
            if (crc & 0x1000000) != 0 {
                crc ^= CRC24_POLY
            }
        }
    }
    return crc & 0xFFFFFF
}

Тогда вы можете сделать либо:

let dataBytes: [UInt8] = ...
let checksum1 = crc(for: dataBytes) // 1890961

Или

let data: Data = ...
let checksum2 = crc(for: data)      // 1890961

В приведенном выше примере я также удалил точки с запятой и использовал более быстрое соглашение об именах методов.

4
Rob 10 Янв 2022 в 18:14