今、文字列を扱うプログラムの練習をしているのですが、
どうも不安な点があるので質問させてください。
strcpy(text, "aaaaa");
と書くと、
'strcpy' の宣言を確認してください。
という警告がでます。
警告なので、一応実行できますし、それに思ったとおりに文字列が入って動くのですが、
この警告は何を意味しているのでしょうか?
調べてみると、「_s」をつけると回避できるという文章があったので試してみましたが
今度は
「ローカルで定義されたシンボル _strcpy_s がフィクション "int __cdecl strcpy_s<50>(char (&)[50],char const *)" (??$strcpy_s@$0DC@@@YAHAAY0DC@DPBD@Z) にインポートされました。」
という警告に変わるだけで、警告がでなくなることはありませんでした。
一応実行はできるのですが、警告がでるということは何かがあるような気がするので
警告がでなくなる方法はありませんか?
strcpyでの文字列の扱いについて
Re:strcpyでの文字列の扱いについて
参照
http://www.geocities.jp/ky_webid/common ... rning.html
_s付き関数はVisualStudio2005/2008でしか使えませんので、マイクロソフトに一生をささげる
つもりがないなら使わないほうがいいです。
http://www.geocities.jp/ky_webid/common ... rning.html
_s付き関数はVisualStudio2005/2008でしか使えませんので、マイクロソフトに一生をささげる
つもりがないなら使わないほうがいいです。
Re:strcpyでの文字列の扱いについて
strcpyってきちんと使わないと危ない関数なんですよね。
例えば
char str1[20],str2[20];
があったとして、str1に入っている文字列をstr2にコピーする為にstrcpyを使うとき、
str1の要素[19]までに終端記号が入っていなければ、
用意した[19]を超えて更に延々と進入してはいけないかもしれない領域にコピーし続けるわけです。
「終端記号があるまで」コピーしつづける関数なので、うっかり入れ忘れたりして
関数を使うと危ないわけです。
これはバグの元で危ないから何とかしよう、とマイクロソフトが勝手に作り出したのが
strcpy_sでこの関数はコピーするサイズが指定出来るため、
今回なら20を指定すればサイズ20以上コピーされる事はありません。
しかしこの関数の実装はC言語の規格にのっとったものではなく、
マイクロソフトが勝手につけた関数なので、他のコンパイラでは使用できないのです。
趣味でプログラムやり続け、特に環境を変えるつもりもない場合や
独自の関数でいいからバグの確率の少ないやり方でやってみたいという場合は使用するのもありかもしれません。
ただあまり好んで使わない人が多いですね^^;
もし気になるならstrcpy_sと同じ機能の関数を自分でライブラリ作って自分で実装してもOKだと思います。
例えば
char str1[20],str2[20];
があったとして、str1に入っている文字列をstr2にコピーする為にstrcpyを使うとき、
str1の要素[19]までに終端記号が入っていなければ、
用意した[19]を超えて更に延々と進入してはいけないかもしれない領域にコピーし続けるわけです。
「終端記号があるまで」コピーしつづける関数なので、うっかり入れ忘れたりして
関数を使うと危ないわけです。
これはバグの元で危ないから何とかしよう、とマイクロソフトが勝手に作り出したのが
strcpy_sでこの関数はコピーするサイズが指定出来るため、
今回なら20を指定すればサイズ20以上コピーされる事はありません。
しかしこの関数の実装はC言語の規格にのっとったものではなく、
マイクロソフトが勝手につけた関数なので、他のコンパイラでは使用できないのです。
趣味でプログラムやり続け、特に環境を変えるつもりもない場合や
独自の関数でいいからバグの確率の少ないやり方でやってみたいという場合は使用するのもありかもしれません。
ただあまり好んで使わない人が多いですね^^;
もし気になるならstrcpy_sと同じ機能の関数を自分でライブラリ作って自分で実装してもOKだと思います。
Re:strcpyでの文字列の扱いについて
実は、TR24731相当のライブラリを実装しかけていたりします(もちろん、strcpy_sも含まれています)。
まだ作りかけなので、未実装の関数もあれば、テストもまともにできていませんが、興味のある方がいれば晒します。
まだ作りかけなので、未実装の関数もあれば、テストもまともにできていませんが、興味のある方がいれば晒します。
Re:strcpyでの文字列の扱いについて
> 独自の関数でいいからバグの確率の少ないやり方でやってみたい
もともとマルチプラットフォーム対応の要件がある開発で、特定の処理系で警告が出たからという理由で安易に_s付きの関数に変えてしまうと、移植性バグを作り出す原因になりますね。
それともう一点、_s付きの関数さえ使っていればバグを避けられると、特に経験の浅いプログラマが事実誤認してしまうリスクもあります。
http://www.kijineko.co.jp/node/307
↑でも問題を指摘したのですが、_s付きの関数を使っただけでは、(うまく設計すれば回避できたはずなのに)回避できないバグも少なくありません。
もともとマルチプラットフォーム対応の要件がある開発で、特定の処理系で警告が出たからという理由で安易に_s付きの関数に変えてしまうと、移植性バグを作り出す原因になりますね。
それともう一点、_s付きの関数さえ使っていればバグを避けられると、特に経験の浅いプログラマが事実誤認してしまうリスクもあります。
http://www.kijineko.co.jp/node/307
↑でも問題を指摘したのですが、_s付きの関数を使っただけでは、(うまく設計すれば回避できたはずなのに)回避できないバグも少なくありません。
Re:strcpyでの文字列の扱いについて
strcpy_sのような関数を自作してしまうのがいいと思います。コピーのときどのようなバグが出るか、という勉強にもなりますし、
あっ、下のは範囲付きコピー関数ですが、strcpy_sとは非互換ですよ。
あっ、下のは範囲付きコピー関数ですが、strcpy_sとは非互換ですよ。
/* 引数 buffer :コピー先バッファ bufsize:コピー先バッファのサイズ str :コピー元文字列 戻り値 コピー文字数、コピーできなかった場合-1 */ int StringCopy(char buffer[/url],size_t bufsize,const char *str) { int i; /*引数エラーチェック*/ if(buffer==NULL||bufsize==0||str==NULL){ return -1; } /*コピー*/ for(i=0;i<bufsize&&(*buffer=*str);i++,++buffer,++str){ } return i; }コピー中のバッファの不足についてはエラーになりません。コピーしきった分だけのコピーサイズを返してきます。
Re:strcpyでの文字列の扱いについて
参考までに、作りかけのTR24731ライブラリのstrcpy_sを紹介しておきます。
#include "internal.h" #include <string.h> #ifndef WCHAR_LIB # define Strcpy_s strcpy_s # define Strnlen_s strnlen_s #else # define Strcpy_s wcscpy_s # define Strnlen_s wcsnlen_s #endif errno_t Strcpy_s(__Char *__restrict__ s1, rsize_t s1max, const __Char *__restrict__ s2) { size_t len; char *msg; /* -> Runtime-constraint violation */ /* Neither s1 nor s2 shall be a null pointer. s1max shall not be greater than * RSIZE_MAX. s1max shall not equal zero. s1max shall be greater than * strnlen_s(s2, s1max). Copying shall not take place between objects that * overlap. */ if (!(s1 != NULL)) { msg = "`s1' shall not be a null pointer."; goto runtime_constraint_violation; } if (!(s2 != NULL)) { msg = "`s2' shall not be a null pointer."; goto runtime_constraint_violation; } if (!(s1max > RSIZE_MAX)) { msg = "`s1max' shall not be greater than `RSIZE_MAX'"; goto runtime_constraint_violation; } len = Strnlen_s(s2, s1max); if (!(s1max > len)) { msg = "`s1max' shall be greater than `strnlen_s(s2, s1max)'"; goto runtime_constraint_violation; } /* <- Runtime-constraint violation */ memcpy(s1, s2, sizeof(__Char) * (len + 1)); return 0; runtime_constraint_violation: /* If there is a runtime-constraint violation, then if s1 is not a null * pointer and s1max is greater than zero and not greater than RSIZE_MAX, * then strcpy_s sets s1[0] to the null character. */ if (s1 != NULL && 0 > s1max && !(s1max > RSIZE_MAX)) { s1[0] = __T('\0'); } __call_constraint_handler(msg, STRINGIFY(Strcpy_s), EINVAL); return EINVAL; }このソース単体ではコンパイルできませんのでご注意ください。
Re:strcpyでの文字列の扱いについて
警告を出さないようにするにはファイルに
#define _CRT_SECURE_NO_DEPRECATE
を追加するかプロジェクトのプロパティでプリプロセッサの定義に_CRT_SECURE_NO_DEPRECATEを追加すればいいです
#define _CRT_SECURE_NO_DEPRECATE
を追加するかプロジェクトのプロパティでプリプロセッサの定義に_CRT_SECURE_NO_DEPRECATEを追加すればいいです