0Pricing
Swift Academy · Lección

withUnsafeBytes e interoperabilidad con C

Conecte con API de C que esperan bytes sin procesar.

withUnsafeBytes e interoperabilidad con C es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.

De valores tipados a bytes sin procesar

A veces necesita ver un valor no como un Int o una struct, sino como una secuencia de bytes sin procesar, por ejemplo para calcular su hash, escribirlo en un archivo o pasarlo a una API de C. withUnsafeBytes le proporciona exactamente eso: una vista temporal del almacenamiento de un valor como UInt8.

var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { rawBuffer in
    print(rawBuffer.count) // 4 bytes
}

El UnsafeRawBufferPointer

El closure recibe un UnsafeRawBufferPointer: un búfer de bytes sin tipo de elemento. Puede indexarlo para leer valores UInt8 individuales. Es de solo lectura; la variante mutable es withUnsafeMutableBytes.

var value: UInt32 = 0x01020304
withUnsafeBytes(of: &value) { bytes in
    for b in bytes { print(String(format: "%02x", b)) }
}
// Order depends on endianness

El orden de los bytes es importante

El orden de bytes que observa depende del orden de bytes de la plataforma. En las máquinas little-endian (Apple silicon e Intel), el byte menos significativo aparece primero. Al serializar para un protocolo, realice la conversión explícitamente con bigEndian o 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))
}

Bytes de una estructura

withUnsafeBytes(of:) funciona con cualquier valor, incluidas las estructuras. La longitud del búfer es igual a MemoryLayout<T>.size, e incluye los bytes de relleno, aunque su contenido no está especificado.

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
}

Cargar un valor desde bytes

Para reinterpretar bytes sin procesar como un valor tipado, utilice load(fromByteOffset:as:) en un búfer sin procesar. El desplazamiento debe respetar la alineación del tipo y los bytes deben representar realmente un valor válido de ese tipo.

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 para datos empaquetados

Los formatos binarios suelen empaquetar campos sin relleno de alineación. Llamar a load en un desplazamiento sin alinear produce un comportamiento indefinido; utilice loadUnaligned(fromByteOffset:as:) para leer de forma segura desde cualquier desplazamiento.

let packet: [UInt8] = [0xFF, 0x04, 0x03, 0x02, 0x01]
let field = packet.withUnsafeBytes { ptr in
    ptr.loadUnaligned(fromByteOffset: 1, as: UInt32.self)
}
print(field)

Conectar Data de Swift con C

Muchas funciones de C aceptan un const void * y una longitud. Data y los arrays exponen withUnsafeBytes, de modo que puede pasar baseAddress y count directamente, sin copiar.

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)
    }
}

Recibir un puntero de C

Cuando una callback de C le proporciona un const void * y una longitud, encapsúlelo en un UnsafeRawBufferPointer para iterar de forma segura. Swift importará el puntero de C como 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 y reinterpretación

Para tratar una región sin procesar como elementos tipados, bindMemory(to:capacity:) indica al compilador cómo debe interpretarla. Utilizarlo incorrectamente (vincular la misma memoria a dos tipos incompatibles) infringe las reglas de aliasing estricto de Swift y produce un comportamiento indefinido.

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 frente a bindMemory

bindMemory cambia permanentemente la forma en que se interpreta la memoria; assumingMemoryBound(to:) afirma que ya está vinculada a ese tipo sin modificar nada. Utilice esta última únicamente cuando tenga la certeza de cuál es la vinculación existente, por ejemplo, en una memoria que sabe que contiene el tipo indicado.

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
}

Lista de comprobación de seguridad

La interoperabilidad con bytes sin procesar y C es donde suelen ocultarse la mayoría de los fallos. Recuerde:

  • No permita nunca que el puntero del closure escape.
  • Respete la alineación o utilice las variantes Unaligned.
  • Gestione explícitamente el endianness al serializar.
  • No vuelva a vincular la memoria a tipos incompatibles.
  • Compruebe que baseAddress no sea nil en los búferes vacíos.
// 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()
    }
}

Comprobación rápida

Compruebe cuánto ha comprendido sobre la lectura de datos binarios empaquetados.

Resumen

Ha aprendido a conectar valores de Swift y C mediante bytes sin procesar:

  • withUnsafeBytes(of:) ofrece una vista de cualquier valor como UInt8.
  • load / loadUnaligned reinterpretan los bytes como valores tipados respetando la alineación.
  • Data y los arrays exponen withUnsafeBytes para pasar un puntero y una longitud a C.
  • bindMemory y assumingMemoryBound controlan cómo se tipa la memoria sin procesar.
  • El orden de bytes, la alineación y el escape del puntero son los principales riesgos.

Preguntas frecuentes

¿La lección «withUnsafeBytes e interoperabilidad con C» es gratis?

Sí — el texto completo de «withUnsafeBytes e interoperabilidad con C» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué aprenderé en «withUnsafeBytes e interoperabilidad con C»?

Conecte con API de C que esperan bytes sin procesar. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «withUnsafeBytes e interoperabilidad con C»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. MemoryLayout y alineación
  2. UnsafePointer y UnsafeMutablePointer
  3. Punteros de búfer inseguros
  4. withUnsafeBytes e interoperabilidad con C
← Volver a Swift Academy