雑記
リテラル
最終更新:
匿名ユーザー
-
view
てなわけで文字列の話。
文字列リテラルは、静的かつconstな配列として確保されるということを前に書いた。
具体的には、以下のようなコードがあったとすると
printf("AAA"); printf("BBB"); printf("CCC");
メモリ上の該当箇所をバイナリで見ると
41 41 41 00 42 42 42 00 43 43 43 00(←もちろんヘキサ)
という風に確保される。
ということは、
char cHoge[10]; memcpy(cHoge, "AAA", sizeof(cHoge)); printf("BBB"); printf("CCC");
というコードを実行するとcHogeには
41 41 41 00 42 42 42 00 43 43
という数値が格納されることになる。
途中にnull文字が入っているためcHogeを文字列として扱う分にはエラーは発生しないけれど、これは明らかなバグである。
「文字列なんだから、strcpy()使えばいいじゃん」 とおっしゃる方は多いだろう。
けど、strcpy()は恐ろしい関数である。
どう恐ろしいかは、以下に具体例を示す。
どう恐ろしいかは、以下に具体例を示す。
char cPiyo[5]; char* cp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; strcpy(cPiyo, cp);
こんなことをしてしまうと、cPiyoは5バイトの領域しかないのに28バイト(null文字終端含む)をコピーしてしまい、後ろの23バイト分の領域を破壊してしまうことになる。
十分なバッファを持っておくならば危険性は軽減されるが、根本的な解決になっていない上、ターゲットによってはメモリに余裕がないこともあり、そうそう無駄な領域を確保しておけない。
また、関数内でローカルに文字列を扱う場合など、不用意にでかいバッファをオート変数で確保しようものなら場合によってはスタックオーバーフローを起こしかねない。
基本的に、文字列は中身を編集したいとかの理由で領域をコピーしたいとき意外はポインタでやり取りするべきだと考える。
そうでない場合は、文字列は可変長なデータなので、そのサイズや終端については、プログラマが意識して使わないといけないのだ。C言語は、「先っぽ」しか提供してくれないのだから。
したがって文字列をコピーしたい場合には、プログラマが毎回気を使ってやる。この辺のエラー処理などを面倒だと思うかそうでないかは、結構重要なところだと思う。
char cPiyo[5]; char* cp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* cPiyoを初期化 */ memset(cPiyo, 0x00, sizeof(cPiyo)); /* サイズを比較、処理を分岐 */ if(sizeof(cPiyo) < strlen(cp)) { memcpy(cPiyo, cp, sizeof(cPiyo); cPiyo[sizeof(cPiyo) - 1] = '\0'; /*null文字を付加*/ } else { strcpy(cPiyo, cp); }
こんな感じ。
文字列には、(というよりstr系関数には)気をつけましょう。下手するとすぐにプログラム暴走するっスよ。