none
Visual C++ 2010で、isspace関数を使うと、実行時エラーが発生します。 RRS feed

  • 質問

  • こんにちは。
    現在、Windows7で、Visual C++ 2010 Expressを使っています。

    Borland C++ CompilerなどのC++コンパイラを使って、
    EXEプログラムをビルドしていた時は、
    isspace関数は、ctype.hをインクルードすると使えていました。
    ところが、isspace関数を使うプログラムを、Visual C++ 2010 Expressでビルドし、
    [Ctrl]+[F5]とタイプして実行してみると、エラーが発生します。
    その時に現れるウィンドウは、下記のURLの通りです。
    https://skydrive.live.com/#cid=3B9CFAE284919667&id=3B9CFAE284919667%2115561
    どうやら、
    (unsigned)(c + 1) <= 256)
    は、isctype.cというファイルの56行目の
    _ASSERTE((unsigned)(c + 1) <= 256);
    という行の事を指しているようなのですが、
    _ASSERTE が何者なのかが分かりませんでした。

    以上の件について何かご存知の方がいらっしゃれば、是非教えて頂きたいと思います。
    では、よろしくお願い致します。

    2012年11月24日 7:48

回答

  • 問題は解決したようですが、根本の原因を理解できていないように思います。

    Visual C++の文字の型としてはchar、wchar_t、TCHARの3種類があります。C++ の文字セットとその中のTchar.h における汎用テキストのマッピング辺りを読み理解することをお勧めします。

    isspace()は過去との互換性のため引数がchar型ではなくint型になっており、またchar→int、wchar_t→int、TCHAR→intいずれも暗黙の型変換が可能なため、間違った文字型を渡してもコンパイラーが警告を出すことができません。そのために実行時エラーとなります。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月25日 2:36
  • 式を評価し、結果が False の場合はデバッグ レポートを生成します。

    http://msdn.microsoft.com/ja-jp/library/ezb1wyez%28v=vs.100%29.aspx

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 8:42
  • char 型(0 - 255)の範囲外の値を渡していないか確認してください。
    (あとは、wchar_t バージョン(iswspace) と使い分けあたりかな)

    2012年11月24日 10:27
    モデレータ
  • 使い方の誤りです。

    http://msdn.microsoft.com/ja-jp/library/y13z34da%28v=vs.100%29.aspx

    CRT デバッグ ライブラリを使用すると、isspace は EOF ではないパラメーターまたは 0 ~ 0xFF の範囲にないパラメーターを渡された場合に CRT アサートを表示します。CRT デバッグ ライブラリ以外で使用する場合、isspace はパラメーターを配列のインデックスとして使用し、パラメーターが EOF ではない場合、または 0 ~ 0xFF の範囲にない場合に未定義の結果を返します。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 15:31
  • 渡していないはずなのですが、

    せっかく CRT がプログラムを中断して通知してくれているのですから、そのときデバッガで、実際に渡している値を確認したほうがよいかと思います。

    そうしなければ、今後もこのようなことが繰り返されるでしょうし。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 17:54
  • isspace関数には、char型変数しか渡していないので、

    char型の罠にはまっている気がします。

    以下のようなコードを書いていませんか?

    #include <cctype>
    
    int main()
    {
    	char c = 0x80;
    	std::isspace(c);
    }
    

    isspace()関数はEOFを受けられるようにint型を引数に取ります。

    また、Visual C++のchar型は符号付きです。

    従って、char型の値を渡そうとすると、int型へ拡張されて0xffffff80~0x0000007fへと変換されます。

    このため、「_ASSERTE((unsigned)(c + 1) <= 256)」に引っかかることになります。


    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月25日 9:10
  • 先に挙げたページをよく読んでください。

    プログラムで扱っている文字・文字列で使用されているエンコーディング・文字コードは何ですか? 文字コードが違えば判定式も異なり、当然ながらそれは使用する関数も異なります。

    isspace()のドキュメントにも

    • TCHAR向けの_istspace()
    • マルチバイト文字を含まないchar向けのisspace()
    • マルチバイト文字を含むchar向けの_ismbcspace()
    • UNICODEを格納するwchar_t向けのiswspace()

    の4つが挙げられています。isspace()を使うなら全角文字を含んでいてはいけません。

    • 回答の候補に設定 佐伯玲 2012年11月28日 6:38
    • 回答としてマーク 佐伯玲 2012年12月4日 4:35
    2012年11月26日 1:12
  • 文字コードがUnicodeではないのに、iswspace関数が使えたのはどうしてなのかわからないですが、

    マルチバイト文字の1バイトを格納するchar型変数に対しては、iswspace関数を使えばよいようです。

     「偶然」使えたにすぎませんので、文字のエンコーディングがわかっている場合は、そのエンコーディングに対応した関数を使用すべきです。そうしないと、また原因不明なエラーの元になります。

    > マルチバイト文字の1バイトを格納するchar型変数に対しては、iswspace関数を使えばよいようです。

    この部分に関してchar型を使用しているのであれば、佐祐理さんが上で例に挙げているように
    マルチバイト文字を含むchar向けの_ismbcspace()
    を使用すべきで、
    UNICODEを格納するwchar_t向けのiswspace()

    は使用すべきではありません。

    • 回答の候補に設定 佐伯玲 2012年11月28日 6:38
    • 回答としてマーク 佐伯玲 2012年12月4日 4:35
    2012年11月26日 7:54

すべての返信

  • 式を評価し、結果が False の場合はデバッグ レポートを生成します。

    http://msdn.microsoft.com/ja-jp/library/ezb1wyez%28v=vs.100%29.aspx

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 8:42
  • char 型(0 - 255)の範囲外の値を渡していないか確認してください。
    (あとは、wchar_t バージョン(iswspace) と使い分けあたりかな)

    2012年11月24日 10:27
    モデレータ
  • 使い方の誤りです。

    http://msdn.microsoft.com/ja-jp/library/y13z34da%28v=vs.100%29.aspx

    CRT デバッグ ライブラリを使用すると、isspace は EOF ではないパラメーターまたは 0 ~ 0xFF の範囲にないパラメーターを渡された場合に CRT アサートを表示します。CRT デバッグ ライブラリ以外で使用する場合、isspace はパラメーターを配列のインデックスとして使用し、パラメーターが EOF ではない場合、または 0 ~ 0xFF の範囲にない場合に未定義の結果を返します。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 15:31
  • 御回答ありがとうございます。

    isspace関数には、char型変数しか渡していないので、
    「EOF ではないパラメーターまたは 0 ~ 0xFF の範囲にないパラメーター」
    は、渡していないはずなのですが、なぜか「CRT アサート」が表示されているようです。
    どうしてもエラーが取り除けないので、以下のような関数で代用しておきました。

    bool my_isspace(char ch){
     if(ch==' ' || ch=='\n' || ch=='\r' || ch=='\t' || ch=='\v'){
      return true;
     }
     else{
      return false;
     }
    }

    2012年11月24日 16:49
  • 御回答ありがとうございます。

    isspaceを、iswspaceに置換してからリビルドし、プログラムを実行すると、エラーが出なくなりました。

    プラットフォームとの互換性が関係しているのかもしれないですね。

    2012年11月24日 16:54
  • 御回答ありがとうございます。

    MSDN全体を対象に、「_ASSERTE」というワードで検索をかけるという手がありましたね。

    以後、そうさせて頂きます。


    • 編集済み kei-k0625 2012年11月24日 16:56
    2012年11月24日 16:56
  • 渡していないはずなのですが、

    せっかく CRT がプログラムを中断して通知してくれているのですから、そのときデバッガで、実際に渡している値を確認したほうがよいかと思います。

    そうしなければ、今後もこのようなことが繰り返されるでしょうし。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月24日 17:54
  • 問題は解決したようですが、根本の原因を理解できていないように思います。

    Visual C++の文字の型としてはchar、wchar_t、TCHARの3種類があります。C++ の文字セットとその中のTchar.h における汎用テキストのマッピング辺りを読み理解することをお勧めします。

    isspace()は過去との互換性のため引数がchar型ではなくint型になっており、またchar→int、wchar_t→int、TCHAR→intいずれも暗黙の型変換が可能なため、間違った文字型を渡してもコンパイラーが警告を出すことができません。そのために実行時エラーとなります。

    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月25日 2:36
  • isspace関数には、char型変数しか渡していないので、

    char型の罠にはまっている気がします。

    以下のようなコードを書いていませんか?

    #include <cctype>
    
    int main()
    {
    	char c = 0x80;
    	std::isspace(c);
    }
    

    isspace()関数はEOFを受けられるようにint型を引数に取ります。

    また、Visual C++のchar型は符号付きです。

    従って、char型の値を渡そうとすると、int型へ拡張されて0xffffff80~0x0000007fへと変換されます。

    このため、「_ASSERTE((unsigned)(c + 1) <= 256)」に引っかかることになります。


    • 回答としてマーク 佐伯玲 2012年12月4日 4:36
    2012年11月25日 9:10
  • せっかく CRT がプログラムを中断して通知してくれているのですから、そのときデバッガで、実際に渡している値を確認したほうがよいかと思います。

    なるほど、こういう場合にデバッガを使うと便利ですね。

    今後はそうさせて頂きます。

    2012年11月25日 20:00
  • Visual C++の文字の型としてはchar、wchar_t、TCHARの3種類があります。C++ の文字セットとその中のTchar.h における汎用テキストのマッピング辺りを読み理解することをお勧めします。

    原因が分かりました。

    全角文字の1バイト目を読み込むときに、isspace関数に渡す値が

    「-126」となっていて、これが原因で、

    「_ASSERTE((unsigned)(c + 1) <= 256)」

    に引っかかったようです。

    isspace関数の代わりに、iswspace関数を使うと、

    エラーが出なくなったことから考えると、

    全角文字の一部を、変数に格納する事がある場合は、

    char型ではなくて、whar_t型の変数を使わなくてはならないという事なのでしょうか?

    • 編集済み kei-k0625 2012年11月25日 20:36
    2012年11月25日 20:22
  • 先に挙げたページをよく読んでください。

    プログラムで扱っている文字・文字列で使用されているエンコーディング・文字コードは何ですか? 文字コードが違えば判定式も異なり、当然ながらそれは使用する関数も異なります。

    isspace()のドキュメントにも

    • TCHAR向けの_istspace()
    • マルチバイト文字を含まないchar向けのisspace()
    • マルチバイト文字を含むchar向けの_ismbcspace()
    • UNICODEを格納するwchar_t向けのiswspace()

    の4つが挙げられています。isspace()を使うなら全角文字を含んでいてはいけません。

    • 回答の候補に設定 佐伯玲 2012年11月28日 6:38
    • 回答としてマーク 佐伯玲 2012年12月4日 4:35
    2012年11月26日 1:12
  • プログラムで扱っている文字・文字列で使用されているエンコーディング・文字コードは何ですか? 文字コードが違えば判定式も異なり、当然ながらそれは使用する関数も異なります。

    isspace関数を使用していたソースファイルのエンコーディングシステムおよび文字コードは、Shift-JISです。

    文字コードがUnicodeではないのに、iswspace関数が使えたのはどうしてなのかわからないですが、

    マルチバイト文字の1バイトを格納するchar型変数に対しては、iswspace関数を使えばよいようです。

    2012年11月26日 6:35
  • 文字コードがUnicodeではないのに、iswspace関数が使えたのはどうしてなのかわからないですが、

    マルチバイト文字の1バイトを格納するchar型変数に対しては、iswspace関数を使えばよいようです。

     「偶然」使えたにすぎませんので、文字のエンコーディングがわかっている場合は、そのエンコーディングに対応した関数を使用すべきです。そうしないと、また原因不明なエラーの元になります。

    > マルチバイト文字の1バイトを格納するchar型変数に対しては、iswspace関数を使えばよいようです。

    この部分に関してchar型を使用しているのであれば、佐祐理さんが上で例に挙げているように
    マルチバイト文字を含むchar向けの_ismbcspace()
    を使用すべきで、
    UNICODEを格納するwchar_t向けのiswspace()

    は使用すべきではありません。

    • 回答の候補に設定 佐伯玲 2012年11月28日 6:38
    • 回答としてマーク 佐伯玲 2012年12月4日 4:35
    2012年11月26日 7:54
  • こんにちは、kei-k0625 さん
    フォーラムオペレータの佐伯 玲 です。

    その後の状況はいかがでしょうか?
    さて、MSDN フォーラムではご質問が解決した際にそれに至る情報に「回答としてマーク」して頂くようにお願いさせていただいております。
    マークが付くことによりそのご質問が解決してスレッドとして区切りがついたことやタイトルの問いに対する答えがスレッドに存在していることを表します。

    フォーラムでは質問が解決した後もタイトルを見て同じように疑問を持たれた方等がその後は質問をせずとも回答がついているスレッドを見れば参考に出来るようにすることも目的としています。
    また、kei-k0625 さんの最後のご返信後にもCatTail さんから追加の情報も寄せられているのでご確認の上、解決に至った場合には過去の情報を含め「回答としてマーク」をお願いいたします。
    「回答としてマーク」はスレッド内で複数の返信につける事が可能です。

    今回は一旦私のほうで参考になると思われる情報に「回答としてマーク」をさせていただきました。

    宜しくお願い致します。
    __________________________
    日本マイクロソフト株式会社 フォーラム オペレータ 佐伯 玲


    • 編集済み 佐伯玲 2012年12月4日 4:35
    2012年11月30日 1:37