首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Swift 與 C 指標互操作完整指南:參數傳遞、陣列、字串與安全性

     編輯:更多程式設計知識

Swift 提供完整的 C 指標互操作支援,自動處理常見的標量、陣列、字串轉換。本文詳細說明 inout 參數、陣列指標、字串指標轉換規則與安全性邊界。

1. 標量輸入/輸出參數

C 函式常用指標回傳多個值,Swift 以 inout + & 對應:


// C: void getColor(float *r, float *g, float *b, float *a);
// Swift 對應:
var r: Float = 0, g: Float = 0, b: Float = 0, a: Float = 0
getColor(&r, &g, &b, &a)  // 自動建立臨時指標傳遞

// NSError 雙重指標慣用法
var error: NSError?
let success = fileManager.contentsOfDirectoryAtPath("/usr/bin", error: &error)
if !success { print(error) }

2. 陣列指標轉換

Swift 陣列可直接轉為 C 指標,支援常數/可變指標:


import Accelerate

let a: [Float] = [1, 2, 3, 4]
let b: [Float] = [0.5, 0.25, 0.125, 0.0625]
var result: [Float] = [0, 0, 0, 0]

// vDSP_vadd(const float *A, stride, const float *B, stride, float *C, stride, length)
vDSP_vadd(a, 1, b, 1, &result, 1, 4)
// result = [1.5, 2.25, 3.125, 4.0625]

// 關鍵點:
// - a, b 為常數陣列 → 自動轉為 UnsafePointer (const float*)
// - &result 為可變陣列 → 自動轉為 UnsafeMutablePointer (float*)
// - 步長 stride=1 表示連續陣列

3. 字串指標轉換

Swift String 可隱式轉為 UnsafePointer (即 const char*):


// C: int puts(const char *s);
// C: int open(const char *path, int flags, mode_t mode);
// C: ssize_t write(int fd, const void *buf, size_t count);

puts("Hello from libc")  // 直接傳遞字串字面值

let fd = open("/tmp/test.txt", O_WRONLY | O_CREAT, 0o666)
if fd >= 0 {
    let text = "Hello World"
    write(fd, text, strlen(text))  // text 自動轉為 const char*
    close(fd)
}

編碼:Swift 字串以 UTF-8 編碼傳遞,以 \0 結尾。

4. 指標轉換安全性邊界

⚠️ 以下情況轉換後的指標不安全/無效:

情況風險對策
C 函式保存指標供後續使用指標僅在呼叫期間有效,呼叫結束即失效在 Swift 端保存資料副本,或用全域/靜態變數
多次傳遞同一變數產生不同指標每次轉換產生新的臨時緩衝區改用 withUnsafeMutablePointer 手動控制生命週期
陣列/字串越界存取C 函式不檢查邊界呼叫前確保容量足夠,或用 UnsafeBufferPointer 檢查
非同步/逃逸閉包中使用指標指標可能指向已釋放記憶體用 withExtendedLifetime 延長生命週期

5. 進階:手動指標控制

需精確控制生命週期時,使用 withUnsafe...Pointer 系列:


var value = 42
withUnsafeMutablePointer(to: &value) { ptr in
    // ptr: UnsafeMutablePointer
    // 此閉包內 ptr 保證有效
    c_function(ptr)
}
// 閉包結束後 ptr 失效,value 仍安全

6. 固定記憶體佈局

與 C 結構體對應時,使用 @frozen 或確保屬性順序:


// C: struct Point { float x, y; };
@frozen struct Point {
    var x: Float
    var y: Float
}
// 記憶體佈局與 C 完全一致,可直接轉指標傳遞

7. 全域/靜態變數作為永久指標


// 安全:全域變數位址固定
var globalContext = MyContext()
let kvoContext = withUnsafePointer(to: &globalContext) { $0 }
// kvoContext 可作為永久唯一指標用於 KVO context

最佳實務總結

  1. 優先使用 Swift 原生 API,僅在呼叫 C/Objective-C 時使用指標。
  2. 標量輸出用 inout + &,最安全簡潔。
  3. 陣列傳遞直接用 &array,注意 stride 與連續性。
  4. 字串直接傳遞,編碼為 UTF-8。
  5. 永不 讓 C 端保存 Swift 產生的臨時指標。
  6. 複雜場景用 withUnsafe...Pointer 明確生命週期。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved