int snprintf( char * s, size_t n, const char * format, ... );
という C の関数がある。C99 から標準に加えられたものだ。
名前から想像できると思うが、s で指定したバッファに、format に従って書式化した文字列を最大 n 文字書き込む、というものである(この説明には語弊がある。詳細は後述)。
VC++ には、_snprintf という関数がある。
引数は標準の snprintf と同じだが、関数名の先頭がアンダースコアであることからもわかるように、これは C の標準関数ではなく、VC++ の独自拡張関数である。VC++ は C99 に対応していないためだ。
この2つ(標準の snprintf と VC++ 独自の _snprintf)は、ある一点において挙動が異なる。
それは、書式化した文字列の長さが n 以上だった場合である(ここでは、他バイト文字は考慮せず、1文字1バイトとする)。
標準は、n - 1 文字まで書き込み、最後にナル文字を付加する。つまり、n = 0 でない限り、出力はナル終端されることが保証される。
VC++ 版は、結果の長さが n 文字未満である場合のみ、ナル文字が書き込まれる。
これは、strncpy と似た挙動であると言える。
どちらが安全かと言えば、標準の方だろう。バッファ オーバーフローが大きな問題として取り沙汰される昨今、新しく追加する関数はより安全なものにしておくという判断は分からないでもない。
だが、できれば既存の関数(strncpy)と挙動を合わせて欲しかったと思う。
いや、こんなことを考えるのは、俺が今、ナル終端しないでバッファいっぱいに書き込む必要があるようなシステムを作っているからだというのも、そんなのが異端だということも分かってはいるが。
ちなみに、VC++ 2005 から取り入れられたセキュリティ強化バージョンである _snprintf_s は、書き込むバッファのサイズと、バッファに書き込む最大文字数を別の引数として取り、バッファサイズが書き込み文字数 + 1 以上でなければエラーになる。
従って、バッファには常にナル文字を書き込むスペースがあることになるので、この関数は、指定した最大文字数に加えてナル文字を書き込む(書き込む文字数 + 1 文字が書き込まれ得る)という動きをする。
そういえば、Microsoft は _s バージョンの関数を標準案として提出したという話も聞いたような気がするが、そっちはどうなってるんだろうなぁ。
あと、これは全く余談だが、_lsearch_s は全然セキュアじゃない。