Мне нужно было преобразовать этот заголовок 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 ответ
Как указал Роб Нэпьер, проблема заключается в том, где вы увеличиваете 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
В приведенном выше примере я также удалил точки с запятой и использовал более быстрое соглашение об именах методов.
Похожие вопросы
Новые вопросы
swift
Swift - это безопасный, быстрый и выразительный язык программирования общего назначения, разработанный Apple Inc. для своих платформ и Linux. Swift с открытым исходным кодом. Используйте тег только для вопросов о языковых функциях или необходимости кода в Swift. Используйте теги [ios], [ipados], [macos], [watch-os], [tvos], [cocoa-touch] и [cocoa] для (не зависящих от языка) вопросов о платформах или фреймворках.
octets2 += 1
? Код, который вы заменяете, выполняет^=
с текущим значением, а затем увеличивает значение (x++
). Кажется, вы сначала увеличиваете значение, а затем работаете с ним (++x
). Нет причин дляoctets2
. Чтобы отладить это, запустите исходный код и распечатайте*octets
иcrc
на каждой итерации. Затем сравнивайте это с вашим новым кодом на каждой итерации. В первый раз они не равны, это ваша ошибка. (Это будет первая итерация.)octets2 += 1
иcrc ^= Int(octets2.pointee) << 16;