sprintf
カウンタがうまく回ってなかった。。。
さて、C言語で文字列のコピーしたいとき、しかもstd::string
じゃなくてchar*
で。
これが悩むんだけど、標準ライブラリを使おうとすると
- strcpy
- strncpy
- sprintf/snprintf
この3つになる。
けど、この3つが結構くせ者なのね。
まず、strcpy
。たぶん一番単純。
char *strcpy(char *dest, const char *src);
srcからdestに文字列をコピーするだけなんだけど、srcがdestより大きい場合ってのが問題。
普通にそのままコピーするからdestの範囲じゃないところまで書き込んじゃう。
いわゆるバッファオーバーフロー。
だから、サイズチェックは必須になる。忘れやすいから使わない方がいい。
次に、strncpy
。ちょっとましになった版。
char *strncpy(char *dest, const char *src, size_t n);
さっきのstrcpy
にサイズを示すnが入っていて、一応上のバグはつぶされてる。
けど、この関数に仕様が微妙で
- nを超える文字数がコピーされることはない。
- src の長さが n よりも少ない場合は、 dest の残りは NUL 文字で埋められる。
- srcがnよりも大きい場合、終端文字(NULL)文字は挿入しない
ということでsrcがn文字より大きかった場合、終わりがない文字列に成っちゃうのね。
だから
strncpy(dest, src, sizeof(dest)-1);
とかで確実に終端文字が入るようにしないといけない。
まあ、これはこれでsrcの長さがnより小さかったらNULを入れる処理が入るから、
長いバッファを使ったときにパフォーマンスがわるくなっちゃう。
最後にsprintf
。
int sprintf(char *str, const char *format, ...);
けど、これはstrcpy
と同じ問題を抱えてるからこっちを使おう。
int snprintf(char *str, size_t size, const char *format, ...);
printf
みたくフォーマット指定で文字列を書き込める関数。
フォーマット指定の仕方できっちりした文字列コピーが可能。
sprintf(buf, "%.*s", sizeof(buf)-1, "long-string");
ここでポイントが %.*s
と精度指定すること。
そうしないと%*s
だけだとコピー元の長さによってフォーマットが長くなってしまう。
とこんなことをいろいろ調べて今日も帰りが遅くなってしまった。。。
Comments