C/C++でポインタを使ったバッファアクセスを行うときに、頻繁に使用するのがポインタのインクリメントとデクリメントです。ポインタの加算・減算なので、参照位置を変更することができ、連続したバッファで使用して順次アクセスができます。
この記事では、C/C++のポインタのインクリメント・デクリメントを行うコードを、Swiftではどのように書き換えることができるかを解説します。
Cのコード例
ここでは次のようなCのコードを書き換えます。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void fillSequentialNumber(void *buf, int32_t len) {
uint8_t *p = (uint8_t *)buf;
uint8_t *end = p + len;
for (; p != end; p++) {
*p = (p - (uint8_t *)buf) % 255;
}
}
void dumpBuf(void *buf, int32_t len) {
uint8_t *p = (uint8_t *)buf;
uint8_t *end = p + len;
for (; p != end; p++) {
printf("%02x ", *p);
}
printf("\n");
}
int main(int argc, const char * argv[]) {
uint8_t buf[16] = {0};
fillSequentialNumber(buf, 16);
dumpBuf(buf, 16);
return 0;
}
このコードを実行すると、次のように出力されます。
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
Swiftでのコード例
Swiftで書き換えたコード例が次のコードです。Swiftではインクリメントとデクリメントがなくなったのと、直接ポインタ操作ができないので、そこをインデックスで表現しています。
import Foundation
func fillSequentialNumber(buffer: UnsafeMutableBufferPointer<UInt8>, length: Int) {
var cur = buffer.startIndex
let end = buffer.startIndex.advanced(by: length)
while cur < end {
buffer[cur] = UInt8((cur - buffer.startIndex) % 255)
cur = cur.advanced(by: 1)
}
}
func dump(buffer: UnsafeMutableBufferPointer<UInt8>, length: Int) {
var cur = buffer.startIndex
let end = buffer.startIndex.advanced(by: length)
while cur < end {
print(String(format: "%02x ", buffer[cur]), separator: "", terminator: "")
cur = cur.advanced(by: 1)
}
print("")
}
var buf = [UInt8](repeating: 0, count: 16)
let len = buf.count
buf.withUnsafeMutableBufferPointer { (ptr) -> Void in
fillSequentialNumber(buffer: ptr, length: len)
dump(buffer: ptr, length: len)
}
このコードを実行すると、次のように出力されます。
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
他のやり方もあるとは思うのですが、思想を近づけて見たコードです。
バッファ確保
Cのコードではスタックに16バイトの配列で確保しましたが、SwiftではUInt8の配列で確保しました。Dataを使っても同じです。
バッファへのアクセス
UInt8の配列のバッファにアクセスするには、withUnsafeMutableBufferPointerメソッドを使います。バッファにアクセスするコードはクロージャーで渡すのですが、このときに[UInt8]のメソッドを使えないので、先に長さは取得しておきます。
インクリメントとデクリメントのの置き換え
UnsafeMutableBUfferPointerの要素にアクセスするにはインデックスを使います。インクリメントとデクリメントはインデックスに対して行います。
ここでは、インクリメントの代わりにadvanced(by:)を使いましたが、次のように+=演算子を使って書くこともできます。
cur += 1
まとめ
インデックスの位置変更でCのインクリメントやデクリメントと、同じような考え方のコードを書くことができます。ポインタを直接操作しているのとは違うので、どちらかというと、バッファの要素へのランダムアクセスに近いコードです。
それでも、Cのコードの考え方にも近いコードかなと思います。











