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

著書紹介

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次