withUnsafeBytes와 C 상호 운용
원시 바이트를 요구하는 C API와 연결합니다.
withUnsafeBytes와 C 상호 운용은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
형식 지정 값에서 원시 바이트로
때로는 값을 Int나 struct가 아니라 원시 바이트의 시퀀스로 확인해야 합니다. 값을 해시하거나, 파일에 쓰거나, C 인터페이스에 전달할 때가 그렇습니다. withUnsafeBytes는 값의 저장 공간을 UInt8로 보는 임시 뷰를 정확히 제공합니다.
var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { rawBuffer in
print(rawBuffer.count) // 4 bytes
}UnsafeRawBufferPointer
클로저는 요소 형식이 없는 바이트 버퍼인 UnsafeRawBufferPointer를 받습니다. 첨자로 접근해 개별 UInt8 값을 읽을 수 있습니다. 이 버퍼는 읽기 전용이며, 변경 가능한 형식은 withUnsafeMutableBytes입니다.
var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { bytes in
for b in bytes { print(String(format: "%02x", b)) }
}
// Order depends on endianness엔디언 순서가 중요합니다
관찰되는 바이트 순서는 플랫폼의 엔디언 순서에 따라 달라집니다. 리틀 엔디언 시스템(애플 실리콘, 인텔)에서는 최하위 바이트가 먼저 옵니다. 프로토콜에 맞춰 직렬화할 때는 bigEndian 또는 littleEndian을 사용해 명시적으로 변환하십시오.
let host: UInt32 = 0x01020304
let networkOrder = host.bigEndian
var be = networkOrder
withUnsafeBytes(of: &be) { bytes in
// Always 01 02 03 04 regardless of platform
print(Array(bytes))
}구조체의 바이트
withUnsafeBytes(of:)는 구조체를 포함한 모든 값에서 작동합니다. 버퍼 길이는 MemoryLayout<T>.size와 같으며, 패딩 바이트도 포함되지만 그 내용은 지정되지 않습니다.
struct RGB { var r: UInt8; var g: UInt8; var b: UInt8 }
var color = RGB(r: 255, g: 128, b: 0)
withUnsafeBytes(of: &color) { bytes in
print(bytes[0], bytes[1], bytes[2]) // 255 128 0
}바이트에서 값 읽기
원시 바이트를 형식 지정 값으로 재해석하려면 원시 버퍼에서 load(fromByteOffset:as:)를 사용하십시오. 오프셋은 해당 형식의 정렬 조건을 따라야 하며, 바이트는 실제로 그 형식의 유효한 값을 나타내야 합니다.
let raw: [UInt8] = [0x04, 0x03, 0x02, 0x01]
let n = raw.withUnsafeBytes { ptr in
ptr.load(fromByteOffset: 0, as: UInt32.self)
}
print(String(format: "0x%08x", n))패킹된 데이터에 loadUnaligned 사용하기
이진 형식에서는 정렬 패딩 없이 필드를 배치하는 경우가 많습니다. 정렬되지 않은 오프셋에서 load를 호출하면 정의되지 않은 동작이 발생하므로, 어떤 오프셋에서도 안전하게 읽으려면 loadUnaligned(fromByteOffset:as:)를 사용하십시오.
let packet: [UInt8] = [0xFF, 0x04, 0x03, 0x02, 0x01]
let field = packet.withUnsafeBytes { ptr in
ptr.loadUnaligned(fromByteOffset: 1, as: UInt32.self)
}
print(field)스위프트 데이터를 C와 연결하기
많은 C 함수는 const void *와 길이를 받습니다. Data와 배열은 withUnsafeBytes를 제공하므로 복사하지 않고 baseAddress와 count를 직접 전달할 수 있습니다.
import Foundation
let data = Data([0x68, 0x69]) // "hi"
data.withUnsafeBytes { (raw: UnsafeRawBufferPointer) in
if let base = raw.baseAddress {
// c_consume(base, raw.count)
print("ptr", base, "len", raw.count)
}
}C 포인터 받기
C 콜백에서 const void *와 길이를 전달받으면 안전하게 순회할 수 있도록 UnsafeRawBufferPointer로 감싸십시오. 스위프트는 C 포인터를 UnsafeRawPointer?로 가져옵니다.
func handleC(_ ptr: UnsafeRawPointer, _ len: Int) {
let buffer = UnsafeRawBufferPointer(start: ptr, count: len)
let checksum = buffer.reduce(0) { $0 &+ Int($1) }
print("checksum:", checksum)
}bindMemory와 재해석
원시 영역을 형식 지정 요소로 취급하려면 bindMemory(to:capacity:)로 컴파일러에 해석 방법을 알려야 합니다. 이를 잘못 사용해 동일한 메모리를 서로 호환되지 않는 두 형식에 바인딩하면 스위프트의 엄격한 별칭 지정 규칙을 위반하며 정의되지 않은 동작이 됩니다.
let raw = UnsafeMutableRawPointer.allocate(
byteCount: 8, alignment: 8)
defer { raw.deallocate() }
let typed = raw.bindMemory(to: Int.self, capacity: 1)
typed.pointee = 1234
print(typed.pointee)assumingMemoryBound와 bindMemory
bindMemory는 메모리의 해석 방식을 영구적으로 변경하고, assumingMemoryBound(to:)는 아무것도 변경하지 않은 채 메모리가 이미 해당 형식에 바인딩되어 있다고 단언합니다. 기존 바인딩을 확실히 알고 있을 때만 후자를 사용하십시오. 예를 들어 해당 메모리가 지정한 형식의 값을 담고 있다는 것을 알고 있을 때 사용합니다.
func sumInts(_ raw: UnsafeRawPointer, _ count: Int) -> Int {
let p = raw.assumingMemoryBound(to: Int.self)
var total = 0
for i in 0..<count { total += p[i] }
return total
}안전성 점검 목록
원시 바이트와 C 상호 운용은 대부분의 충돌이 발생하는 부분입니다. 다음을 기억하십시오.
- 클로저의 포인터가 클로저 밖으로 빠져나가게 하지 마십시오.
- 정렬을 준수하거나
Unaligned변형을 사용하십시오. - 직렬화할 때는
endianness를 명시적으로 처리하십시오. - 충돌하는 형식으로 메모리를 다시 바인딩하지 마십시오.
- 빈 버퍼의
nil인baseAddress에 대비하십시오.
// Convert any value to a hex string safely
import Foundation
func hex<T>(_ v: T) -> String {
var value = v
return withUnsafeBytes(of: &value) { bytes in
bytes.map { String(format: "%02x", $0) }.joined()
}
}빠른 확인
패킹된 이진 데이터를 읽는 방법에 대한 이해도를 확인해 보십시오.
복습
원시 바이트를 통해 스위프트 값과 C를 연결하는 방법을 배웠습니다.
withUnsafeBytes(of:)는 모든 값을UInt8로 볼 수 있게 합니다.load/loadUnaligned는 정렬을 준수하면서 바이트를 형식 지정 값으로 재해석합니다.Data와 배열은 C에 포인터와 길이를 전달할 수 있도록withUnsafeBytes를 제공합니다.bindMemory와assumingMemoryBound는 원시 메모리에 형식을 지정하는 방식을 제어합니다.- 엔디언 순서, 정렬, 포인터 이탈이 주요 위험 요소입니다.
AI 튜터와 함께 Swift을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 122
- 레슨
- 409
자주 묻는 질문
“withUnsafeBytes와 C 상호 운용” 강의는 무료인가요?
네 — “withUnsafeBytes와 C 상호 운용” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“withUnsafeBytes와 C 상호 운용”에서 뭘 배우나요?
원시 바이트를 요구하는 C API와 연결합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Swift Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“withUnsafeBytes와 C 상호 운용” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- MemoryLayout과 정렬
- UnsafePointer와 UnsafeMutablePointer
- 안전하지 않은 버퍼 포인터
- withUnsafeBytes와 C 상호 운용