strcpyでの文字列の扱いについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kirbest

strcpyでの文字列の扱いについて

#1

投稿記事 by kirbest » 16年前

今、文字列を扱うプログラムの練習をしているのですが、
どうも不安な点があるので質問させてください。

strcpy(text, "aaaaa");
と書くと、
'strcpy' の宣言を確認してください。
という警告がでます。
警告なので、一応実行できますし、それに思ったとおりに文字列が入って動くのですが、
この警告は何を意味しているのでしょうか?

調べてみると、「_s」をつけると回避できるという文章があったので試してみましたが
今度は
「ローカルで定義されたシンボル _strcpy_s がフィクション "int __cdecl strcpy_s<50>(char (&)[50],char const *)" (??$strcpy_s@$0DC@@@YAHAAY0DC@DPBD@Z) にインポートされました。」
という警告に変わるだけで、警告がでなくなることはありませんでした。
一応実行はできるのですが、警告がでるということは何かがあるような気がするので
警告がでなくなる方法はありませんか?

Mist

Re:strcpyでの文字列の扱いについて

#2

投稿記事 by Mist » 16年前

参照
http://www.geocities.jp/ky_webid/common ... rning.html

_s付き関数はVisualStudio2005/2008でしか使えませんので、マイクロソフトに一生をささげる
つもりがないなら使わないほうがいいです。

管理人

Re:strcpyでの文字列の扱いについて

#3

投稿記事 by 管理人 » 16年前

strcpyってきちんと使わないと危ない関数なんですよね。
例えば

char str1[20],str2[20];

があったとして、str1に入っている文字列をstr2にコピーする為にstrcpyを使うとき、
str1の要素[19]までに終端記号が入っていなければ、
用意した[19]を超えて更に延々と進入してはいけないかもしれない領域にコピーし続けるわけです。
「終端記号があるまで」コピーしつづける関数なので、うっかり入れ忘れたりして
関数を使うと危ないわけです。
これはバグの元で危ないから何とかしよう、とマイクロソフトが勝手に作り出したのが
strcpy_sでこの関数はコピーするサイズが指定出来るため、
今回なら20を指定すればサイズ20以上コピーされる事はありません。

しかしこの関数の実装はC言語の規格にのっとったものではなく、
マイクロソフトが勝手につけた関数なので、他のコンパイラでは使用できないのです。

趣味でプログラムやり続け、特に環境を変えるつもりもない場合や
独自の関数でいいからバグの確率の少ないやり方でやってみたいという場合は使用するのもありかもしれません。
ただあまり好んで使わない人が多いですね^^;

もし気になるならstrcpy_sと同じ機能の関数を自分でライブラリ作って自分で実装してもOKだと思います。

たかぎ

Re:strcpyでの文字列の扱いについて

#4

投稿記事 by たかぎ » 16年前

実は、TR24731相当のライブラリを実装しかけていたりします(もちろん、strcpy_sも含まれています)。
まだ作りかけなので、未実装の関数もあれば、テストもまともにできていませんが、興味のある方がいれば晒します。

たかぎ

Re:strcpyでの文字列の扱いについて

#5

投稿記事 by たかぎ » 16年前

> 独自の関数でいいからバグの確率の少ないやり方でやってみたい

もともとマルチプラットフォーム対応の要件がある開発で、特定の処理系で警告が出たからという理由で安易に_s付きの関数に変えてしまうと、移植性バグを作り出す原因になりますね。

それともう一点、_s付きの関数さえ使っていればバグを避けられると、特に経験の浅いプログラマが事実誤認してしまうリスクもあります。
http://www.kijineko.co.jp/node/307
↑でも問題を指摘したのですが、_s付きの関数を使っただけでは、(うまく設計すれば回避できたはずなのに)回避できないバグも少なくありません。

tk-xleader

Re:strcpyでの文字列の扱いについて

#6

投稿記事 by tk-xleader » 16年前

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での文字列の扱いについて

#7

投稿記事 by たかぎ » 16年前

参考までに、作りかけの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;
}
このソース単体ではコンパイルできませんのでご注意ください。

toyo

Re:strcpyでの文字列の扱いについて

#8

投稿記事 by toyo » 16年前

警告を出さないようにするにはファイルに
#define _CRT_SECURE_NO_DEPRECATE
を追加するかプロジェクトのプロパティでプリプロセッサの定義に_CRT_SECURE_NO_DEPRECATEを追加すればいいです

閉鎖

“C言語何でも質問掲示板” へ戻る