SwiftでCのポインタのインクリメント・デクリメントのコードを書き換える

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のコードの考え方にも近いコードかなと思います。

投稿者プロフィール

林 晃
林 晃macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++使い。豊富な開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。

基礎から学ぶMetal


「基礎から学ぶMetal」を執筆しました。本書はMetalを使ってGPUプログラミングを行うための最初のステップを解説するMetalの解説書です。

私が初めてGPUプログラミングを行ったとき、どこから手をつけて、学んでいけば良いのか分からず呆然としました。もし、あのとき、これを教えてくれればという部分を解説しました。本書で解説している部分はMetalの基礎となる部分で、Metalを使うときに必ず触れることになる部分です。

詳細

基礎から学ぶSwiftUI


「基礎から学ぶ SwiftUI」というタイトルの本を執筆しました。

SwiftUIの入門書です。

SwiftUIのコンセプトは「ユーザーインターフェイスを作るための最短パスを提供する」「一度学べば(Appleのプラットフォームの)どこにでも適用できる」です。

SwiftUIの概要から始まって、一つ一つのテクノロジートピックに注目しながらSwiftUIとは何か?どんなことができるのか?どのようなコードを書けば良いのかなどを丸々一冊使って解説しています。

詳細

関連記事

  1. 「iPadで学ぶ はじめてのプログラミング」の見本誌が届きました

  2. Cのバイナリデータを確保する処理をSwiftで書く

  3. 基礎から学ぶ SwiftUI

    「基礎から学ぶ SwiftUI」を執筆しました

  4. Swift逆引きハンドブックのサンプルのSwift 3対応方法について…

  5. Swiftは開発者を強制的に新しい世界に連れて行く

  6. Ubuntu上でSwiftを使うためにCLionを試してみる

  7. SwiftでのバッファアクセスはwithUnsafeBytesを使う

  8. Swift、オープンソース化、本当に出た!

最近の著書

  1. 基礎から学ぶ SwiftUI

最近の記事