memcpy 复制带偏移量的数组

问题描述 投票:0回答:3

我有一个巨大的数组,我只想复制它的中间部分。我正在尝试使用

memcpy
进行表演,但无法找到这样做的方法。下面是一个例子。我们如何为源提供偏移量?

var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]

memcpy(&dest[2], source, 5)

print(dest) // [0, 0, 1, 2, 3, 4, 5, 0, 0]
// This works
var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]

memcpy(&dest[2], &source[2], 5)

print(dest) // [0, 0, 3, 0, 0, 0, 0, 0, 0]
// Only `source[2]` is copied
swift memcpy
3个回答
2
投票

您可以为此目的使用

replaceSubrange()

let source: [UInt8] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
var dest: [UInt8] =   [0, 0, 0, 0, 0, 0, 0, 0, 0]

dest.replaceSubrange(2..<(2+5), with: source[2..<(2+5)])
print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]

或者简单地将源切片分配给目标切片:

dest[2..<(2+5)] = source[2..<(2+5)]
print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]

基准

在 MacBook Air M2 上,代码在发布配置中编译。

import Foundation

let N = 1_000_000 // Length of source and destination array
let sourceStart = 50
let destinationStart = 2000
let length = 12345

let source: [UInt8] = Array(repeating: 5, count: N)

for _ in 1...10 {
    do {
        var dest: [UInt8] = Array(repeating: 0, count: N)
        let start = Date()
        
        dest[destinationStart...].withUnsafeMutableBufferPointer { p in
            source.copyBytes(to: p, from: sourceStart..<sourceStart + length)
        }
        let end = Date()
        print("copyBytes:      ", end.timeIntervalSince(start) * 1000, "ms")
    }
    do {
        var dest: [UInt8] = Array(repeating: 0, count: N)
        let start = Date()
        
        source[sourceStart...].withUnsafeBytes { sourcePtr in
            dest[destinationStart...].withUnsafeMutableBytes { destPtr in
                _ = memcpy(destPtr.baseAddress, sourcePtr.baseAddress, length)
            }
        }
        
        let end = Date()
        print("memcpy:         ", end.timeIntervalSince(start) * 1000, "ms")
    }
    do {
        var dest: [UInt8] = Array(repeating: 0, count: N)
        let start = Date()
        
        dest.replaceSubrange(destinationStart..<(destinationStart+length),
                             with: source[sourceStart..<(sourceStart+length)])
        
        let end = Date()
        print("replaceSubrange:", end.timeIntervalSince(start) * 1000, "ms")
    }
    do {
        var dest: [UInt8] = Array(repeating: 0, count: N)
        let start = Date()
        
        dest[destinationStart..<(destinationStart+length)]
            = source[sourceStart..<(sourceStart+length)]
        
        let end = Date()
        print("slicing:        ", end.timeIntervalSince(start) * 1000, "ms")
    }
    print()
}

结果:

copyBytes:       0.8690357208251953 ms
memcpy:          0.9009838104248047 ms
replaceSubrange: 0.010013580322265625 ms
slicing:         0.008940696716308594 ms

1
投票

我建议改用 Swift 指针 API。

处理

UInt8
数组时,可以使用
copyBytes
。获取目标数组的一部分(不创建副本),从中获取缓冲区指针,并将源范围复制到该缓冲区。

let destinationStart = 2
let sourceStart = 2
let sourceEnd = 7
dest[destinationOffset...].withUnsafeMutableBufferPointer { p in
    source.copyBytes(to: p, from: sourceStart..<sourceEnd)
}

我认为

memcpy
需要取 2 个切片,并从两个切片中获取指针:

source[sourceStart...].withUnsafeBytes { sourcePtr in
    dest[destinationStart...].withUnsafeMutableBytes { destPtr in
        memcpy(destPtr.baseAddress, sourcePtr.baseAddress, length)
    }
}

-1
投票

似乎在工作:

import Foundation

var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]

memcpy(&dest[2], UnsafePointer<UInt8>(&source) + 2, 5)

print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]

并给出一堆警告:

“UnsafePointer”的初始化导致悬空指针

从“[UInt8]”到“UnsafePointer”的隐式参数转换会产生一个指针,该指针仅在调用“init(_:)”期间有效

在 Array 上使用“withUnsafeBufferPointer”方法,以便将参数显式转换为对定义的范围有效的缓冲区指针

withUnsafePointer 摆脱警告:

import Foundation

var source: [UInt8] = [1,2,3,4,5,6,7,8,9]
var dest: [UInt8] = [0,0,0,0,0,0,0,0,0]

let _ = withUnsafePointer(to: &source[2])
{ 
    memcpy(&dest[2], $0, 5) 
}

print(dest) // [0, 0, 3, 4, 5, 6, 7, 0, 0]

不同的数据类型仍然会有问题。 无论数据类型如何,内存中的步幅似乎都是相同的。

© www.soinside.com 2019 - 2024. All rights reserved.