【问题标题】:Why does the same function in Obj-C return a different result in swift?为什么 Obj-C 中的相同函数在 swift 中返回不同的结果?
【发布时间】:2022-01-10 03:17:29
【问题描述】:

我需要将这个带有函数的 c 头文件转换成一个 swift 脚本。我这样做了,但是当我尝试这两个函数并比较结果时,它们结果是不相等的。到底是怎么回事?我想我已经把它缩小到:这可能是指针在 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")

【问题讨论】:

  • 你在用octets2 += 1做什么?您要替换的代码使用当前值执行^=,然后递增该值 (x++)。您似乎是先增加值,然后再使用它 (++x)。 octets2 没有任何理由。要对此进行调试,请运行原始代码并在每次迭代时打印出*octetscrc。然后在每次迭代时将其与您的新代码进行比较。第一次他们不相等,那是你的错误。 (这将是第一次迭代。)
  • 你的救星。谢谢!当我交换 octets2 += 1crc ^= Int(octets2.pointee) &lt;&lt; 16; 时它起作用了

标签: swift objective-c pointers pgp


【解决方案1】:

正如 Rob Napier 指出的那样,问题在于您在哪里增加 octets2。 Objective-C 在检索到值后递增指针,而 Swift 版本在之前递增它。

但我可能会更进一步,完全消除不安全指针(octetsoctets2)以及 lenl 变量。而是直接传递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
}

或者,如果你想变得花哨,你可以做一个通用的再现,而不是,它将接受任何 SequenceUInt8(即,[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

在上面,我还删除了分号,并使用了更快捷的方法命名约定。

【讨论】:

    猜你喜欢
    • 2017-04-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多