clang: 仮引数を配列にする
2025/09/06
鍵やハッシュを使うと、32バイトのバッファが必要だったり、64バイトのバッファが必要だったり、絶対にこれ以上のサイズを持ったものを引数にしてほしいということがしばしばある。
ポインタとサイズを受け取る
バッファのサイズを教えてもらい、それをチェックする。
libwally-core がこのタイプだ。
たとえば SHA256の関数 はこうなっている。
int wally_sha256(const unsigned char *bytes, size_t bytes_len, unsigned char *bytes_out, size_t len)
関数側でサイズのチェックもできるので安全なのだが、長くなる。
構造体にする
構造体のメンバに必要なサイズの配列を持ってもらい、それを引数にするパターンがある。
私は c-lightning で見かけた。
struct secret {
u8 data[32];
};
bool secret_eq_consttime(const struct secret *a, const struct secret *b);
構造体ではあるがアドレスが配列の先頭アドレスと一致するので、行儀は悪いがキャストしてそのまま使うこともできる。
データの一部を直接与えて代入してほしい、というような使い方はできなくなる。
配列にする
最近、仮引数にサイズを付けた配列にするのもありかと思っている。
構造体にしていても最近のテキストエディタはホバーで中身を見せてくれたりはするのだが、
私はマウスカーソルが乗ってすぐホバーが出ると邪魔なので長めに時間を設定しているため、
ホバーでの参照はあまり使っていないのだ。
見てすぐわかるので、案外よいんじゃないかと思っている。
void txhash_to_txid_string(char txid[TX_TXID_STR_MAX], const uint8_t txhash[WALLY_TXHASH_LEN]);
サイズが違ってもコンパイルエラーにはならないのでちょっと弱いのだが warning は出してくれる。
src/main.c: In function ‘cmd_spend’:
src/main.c:331:5: warning: ‘txhash_to_txid_string’ accessing 65 bytes in a region of size 32 [-Wstringop-overflow=]
331 | txhash_to_txid_string(txid, txhash);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.c:331:5: note: referencing argument 1 of type ‘char *’
In file included from src/main.c:16:
src/include/misc.h:48:6: note: in a call to function ‘txhash_to_txid_string’
48 | void txhash_to_txid_string(char txid[TX_TXID_STR_MAX], const uint8_t txhash[WALLY_TXHASH_LEN]);
| ^~~~~~~~~~~~~~~~~~~~~
あと、キャストして無理やりコンパイラをだますというのもたぶんできない。
できるのかな? やり方が分からなかったが typedef
すればできるだろう。
おまけ: C99 と C11
C99 まではついていってるんじゃないかなあと個人的に思っているのだが、 C11 のことは全然知らない。
wikipedia を見て気付いたのだが、無名共用体とか無名構造体ができるようになったのか(オライリーのCリファレンス本では”無名”ではなく”匿名”を使っていた)。 無名関数はさすがにないか。
C++11 には無名関数というかラムダ関数というか、そういうのが使えるようになったそうだ。
fff のサンプルを見直していたついでに無名関数を使ってみた(コード)。
見よう見まねなので正しい使い方かどうかは分からないが、エラーも出ず動いた。
それまではこんな風に クラスのメンバ関数を static
にして埋め込んでいた。
やっていることはそんなに変わらないだろう。