sentinel
属性について調べてみた。
いつものようにFunction Attributes - Using the GNU Compiler Collection (GCC)を読んでみると、関数宣言に指定して、関数の最後の引数(オプションで引数の位置を指定可能)がNULLになっていることを保障する機能らしい。何が嬉しいんだろうと思って、systemdで使われている場所を見てみると、ほぼすべて、可変引数を取る関数に指定されていた。なるほど。
例えば、systemdにはstrjoin
というユーティリティ関数があるが、これにsentinel
属性が指定されている。
src/shared/util.h
char *strjoin(const char *x, ...) _sentinel_;
joinという名前になっているが、strjoin
は間に文字列を挟む訳ではない。単に、文字列を繋げるだけである。(strcat(3)の高性能版と言える。) 可変引数がすべて文字列だとすると、確かに引数の最後がNULLだと扱いやすいかもしれない。
ちなみにstrjoin
はファイルパスやdbusのオブジェクトパスの文字列を構築するのに便利である。例えば、cgroupsのためのパス文字列の構築に使われている。
src/shared/cgroup-util.c
static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
char *t = NULL;
if (!isempty(controller)) {
if (!isempty(path) && !isempty(suffix))
t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
else if (!isempty(path))
t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
else if (!isempty(suffix))
t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
else
t = strappend("/sys/fs/cgroup/", controller);