わかった わかった 天地がひっくり返るほどの驚き

また Objective-Cの話です

どんなプログラムでもほとんどの場合 「文字列」を使用します 「文字列」とは、実はメモリーの連続した番地に格納されている何らかのデータです

それを人が見れば、”齋藤 滋”のように理解できるのです でも、コンピューターから見れば、これは単なるメモリー中の数字とかプログラムとかと同一程度のデータでしかありません

コンピューターの機械語に非常に近い C言語では、文字列は、そのまま単なる連続アドレスに格納されたデータであり、文字列の最後に「終了マーク」である、0 (ゼロ) というデータが入っています。そして、この文字列は「静的変数」として宣言されたり、「動的に」確保されたりしない限り、メモリー中の「スタック領域」という部分に格納されるのです。

問題は、この「スタック領域」というのはプログラム実行に大切な領域であり、そこには、プログラムの実行に伴って、その他の変数とか、暫定データとか、戻り番地とか、色々と重要なデータも連続して書き込まれていきます。

そのような重要なデータが、例えば “1234”という文字列の次に書き込まれていたとします、この場合メモリーの連続した番地に、’1′, ‘2’, ‘3,’ ‘4’そして終了マークの’0′ が入っています その次には重要データが格納されています

ここでもしも、この文字列を書き換えた場合どうなるでしょうか?

もしも書き換えが”123″であれば、最初の文字列より短いので、’4’のデータが終了マークの’0’となり、’1′, ‘2’, ‘3’, ‘0’, ‘0’ となるだけでそれに引き続く重要データは保護されていて安全です

しかし、例えば “12345”を書き込んだ場合どうなるでしょうか? 当然ながら溢れて (= overflow)しまい、重要データが突然意味の無い ‘0’に書き換えられてしまいます。

こんれば、当然のことながらプログラムは停止したり、意図しない動作をしていました。この原理を巧みに使用している悪意のあるプログラムのことを “バッファー・オーバーフロー攻撃” と呼びます

もちろんプログラムの規模が小さければ、プログラムを書くプログラマーも、この危険性を意識してそのような間違いが起こらないように常に気をつけて書きます しかし、ある程度大きくなれば、どうしても見落としが起こります そして、重大な問題が起こるのです

これに対しては、システム的にそのようなエラーが混入しないようにしないといけません それで、その後出てきた新しいコンピューター言語では一様に、上に述べたような単純な文字列モデルではなく、ストリング (String) というモデル、これをストリング・クラスと呼びますが、それが導入されていて、C言語文字列ではなく、ストリング・クラスを使用することが強制あるいは推奨されています

Objective-Cでは、単純な C文字列も普通に使用できますが、安全なストリング・クラスを使用することが推奨されています それが、NSStringクラスなのです しかし、ここにもう一つ NSMutableStringクラスというのも存在するのです

この違いは何でしょうか? 書籍や解説ホームページでは、大体一様に以下のような説明が書いてあります

「NSStringクラスでは、いったん作成された文字列はその内容を変更することができません」しかし、「NSMutableStringクラスでは、可変な文字列となります」

この説明を読んでああそうなのか、NSString文字列では、C言語文字列のようなもので、buffer overflowを防ぐために、可変ではないのだ、と理解したのです その理解の下では、以下のプログラムは不正となります

NSString* work0 = @"1234";
work0 = [work0 stringAppendByString: @"5"];

// このようにするとはじめのwork0に確保された
// 文字列アドレスの最後に'5'が書き込まれ、
// 重要データが破壊される筈
// 従って言語仕様でエラーにすべき

しかしながら、これが普通にOKなのです えーーー?? どういうこと??

だったらば、NSMutableStringクラスは何なの?  このように重大な疑問を抱きました そして、色々調べてもどうも明確に書いていないのです 何故だろう? 何故だろう? 疑問はどんどん膨らみました

そして、分かったのです 根本的な発想という概念というか世界観の違いなのです これには驚きましたが、そのようなパラダイムの重大な変化に柔軟に着いていける僕の頭脳の柔軟さに嬉しくなりました

そうなのでは Objective-Cでは オブジェクトに何かをさせるための、メソッド呼び出しは、いわゆるメソッド呼び出しではなくって、メッセージの送信なのです つまり、Objective-Cでは、オブジェクトに何かを強制的にやらせる、のではなくって、「これして下さい」というメッセージを送って、「オブジェクトがやる気になれば」それに応えて振る舞うのです

この結果が実際問題どのように違うのでしょうか? 次のプログラムで明らかです

NSString* work1 = [NSString stringWithString: @"1234"];
//
// NSStringの場合通常下記のように初期化する
// NSString* work1 = @"1234";
//
NSMutableString: work2 = [NSMutableString stringWithString: @"1234";
//
// それぞれの変数を@"一二三"で書き換えるために setStringメッセージを送る
//
[work1 setString: @"一二三"];
[work2 setString: @"一二三"];
//
// それぞれの出力結果は
//
NSLog(@"%@", work1); // (1)
NSLog(@"%@", work2); // (2)

(1)の出力は “123”

(2)の出力は “一二三” というようになります つまり、これが可変かどうか? ということなのです

従って、NSStringで (2) と同様の出力を得るためには

work1 = [work1 setString: @"123"];

という風に代入せねばならないのです 何とも気づいてしまえば当たり前の概念ですが、パラダイムが違うので面食らいました

投稿者: (KAMAKURA & SAPPORO)Dr_Radialist

Expert Interventional Cardiologist and Amateur Computer Programmer

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です