0Pricing
Swift Academy · Aula

withUnsafeBytes e Interoperabilidade com C

Faça a ponte com APIs de C que esperam bytes brutos.

withUnsafeBytes e Interoperabilidade com C é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Swift Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Swift Academy inclui 4 aulas no total.

De valores tipados a bytes brutos

Às vezes, você precisa ver um valor não como um Int ou uma struct, mas como uma sequência de bytes brutos — para calcular seu hash, gravá-lo em um arquivo ou passá-lo a uma API de C. withUnsafeBytes oferece exatamente isso: uma visão temporária do armazenamento de um valor como UInt8.

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

O UnsafeRawBufferPointer

O bloco recebe um UnsafeRawBufferPointer — um buffer de bytes sem tipo de elemento. Você o indexa para ler valores individuais de UInt8. Ele é somente de leitura; a forma mutável é withUnsafeMutableBytes.

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

A ordem dos bytes é importante

A ordem dos bytes que você observa depende da ordem dos bytes da plataforma. Em máquinas little-endian (Apple silicon, Intel), o byte menos significativo vem primeiro. Ao serializar para um protocolo, faça a conversão explicitamente com bigEndian ou 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 uma struct

withUnsafeBytes(of:) funciona com qualquer valor, inclusive structs. O comprimento do buffer é igual a MemoryLayout<T>.size, e quaisquer bytes de preenchimento são incluídos, mas seu conteúdo não é 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
}

Carregando um valor a partir de bytes

Para reinterpretar bytes brutos como um valor tipado, use load(fromByteOffset:as:) em um buffer bruto. O deslocamento deve respeitar o alinhamento do tipo, e os bytes precisam representar de fato um valor válido desse 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 dados compactados

Os formatos binários frequentemente compactam campos sem preenchimento de alinhamento. Chamar load em um deslocamento não alinhado resulta em comportamento indefinido; em vez disso, use loadUnaligned(fromByteOffset:as:) para ler com segurança a partir de qualquer deslocamento.

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

Fazendo a ponte entre Data do Swift e C

Muitas funções de C aceitam um const void * junto com um comprimento. Data e os arrays expõem withUnsafeBytes, permitindo passar baseAddress e count diretamente, sem 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)
    }
}

Recebendo um ponteiro de C

Quando um retorno de chamada de C fornece um const void * e um comprimento, envolva-os em um UnsafeRawBufferPointer para iterar com segurança. O Swift importará o ponteiro 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 e reinterpretação

Para tratar uma região bruta como elementos tipados, bindMemory(to:capacity:) informa ao compilador como interpretá-la. Usar isso incorretamente — vinculando a mesma memória a dois tipos incompatíveis — viola as regras estritas de compatibilidade de tipos do Swift e resulta em comportamento 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 e bindMemory

bindMemory altera permanentemente a forma como a memória é interpretada; assumingMemoryBound(to:) afirma que ela já está vinculada a esse tipo, sem alterar nada. Use o segundo somente quando tiver certeza da vinculação existente, como no caso de uma memória que você sabe que contém o tipo fornecido.

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 verificação de segurança

A interoperabilidade entre bytes brutos e C é onde a maioria das falhas se esconde. Lembre-se:

  • Nunca permita que o ponteiro do bloco escape.
  • Respeite o alinhamento ou use as variantes Unaligned.
  • Trate explicitamente a ordem dos bytes ao serializar.
  • Não vincule novamente a memória a tipos conflitantes.
  • Proteja-se contra um baseAddress nil em buffers vazios.
// 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()
    }
}

Verificação rápida

Teste sua compreensão da leitura de dados binários compactados.

Recapitulação

Você aprendeu a fazer a ponte entre valores do Swift e C por meio de bytes brutos:

  • withUnsafeBytes(of:) apresenta qualquer valor como UInt8.
  • load / loadUnaligned reinterpretam bytes como valores tipados, respeitando o alinhamento.
  • Data e os arrays expõem withUnsafeBytes para passar ponteiro + comprimento ao C.
  • bindMemory e assumingMemoryBound controlam como a memória bruta é tipada.
  • A ordem dos bytes, o alinhamento e o escape do ponteiro são os principais riscos.

Perguntas Frequentes

A aula “withUnsafeBytes e Interoperabilidade com C” é grátis?

Sim — o texto completo de “withUnsafeBytes e Interoperabilidade com C” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Swift Academy, atualize para CoddyKit PRO. O curso de Swift Academy inclui 4 aulas no total.

O que vou aprender em “withUnsafeBytes e Interoperabilidade com C”?

Faça a ponte com APIs de C que esperam bytes brutos. Você pratica Swift Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Swift Academy?

Nenhuma experiência prévia é necessária. Swift Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “withUnsafeBytes e Interoperabilidade com C”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Swift Academy?

Sim. Cada aula de Swift Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. MemoryLayout e Alinhamento
  2. UnsafePointer e UnsafeMutablePointer
  3. Ponteiros de Buffer Inseguros
  4. withUnsafeBytes e Interoperabilidade com C
← Voltar para Swift Academy