̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ IT ニュース&コラム 2015/ 8/10 通巻693号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ポインター宣言を表す * を変数に付けるな - リーダブル・コード(38) C言語を学習するときに最も難しいのが、ポインターです。 その原因の1つが、 ポインター宣言を表す記号「*」を変数に付けなければならないケースがある 文法です。 このケースによって、ポインター宣言を表す記号「*」を変数に付けることが 定義であると思われていて、初心者向けの教科書に書いてあるサンプル コード もそうなっていることが多いです。 はたして、定義(と思われていること)に 基づいて教えたりルールを作ったほうがよいのか考えてみましょう。 「*」は、変数に付けても、型に付けても、どちらの書き方でも構いません。   int *p; /* (1) 変数に付ける書き方、p はポインター型 */   int* p; /* (2) 型に付ける書き方、p はポインター型 */ しかし、1つの宣言文( ; まで)に2つ以上の変数を宣言するときは、そうでは ありません。 ポインター宣言をあらわす記号「*」を変数に付けることを 想定した文法であることが表面に出てきます。   int *p1, *p2; /* (3) p1, p2 ともポインター型 */   int* p1, p2; /* (4) p1 はポインター型、p2 は int 型 */ 確かに、(4) の書き方では、p2 がポインター型であると読み間違えてしまう でしょう。 これは問題だ、ということで問題が起きないために (3) の書き方を コーディング ルールにしようと考える人が多いようです。 しかし、これは悪い コーディング ルール(悪法)です。 なぜ悪いのかを説明しましょう。 ところで、C# 言語(5)では、(4)と同じ書き方でも、p2 もポインター型になります。   int* p1, p2; /* (4) p1 はポインター型、p2 は int 型 (C/C++言語) */   int* p1, p2; /* (5) p1, p2 ともポインター型 (C#言語) */ C#言語を設計した人は C言語の文法に問題があったから変更したと思いますが、 C言語を設計した人も何らかの考えがあったはずです。 それは、「宣言と使用の文法を一致させる方針」と言われています。(出典不明)   int *p; /* p に * 演算子(間接演算子)を付けると int 型になる */   int f(); /* f に ( ) 演算子を付けると int 型になる(の値を返す) */   int a[3]; /* f に [ ] 演算子を付けると int 型になる */ その方針で考えると見事に辻褄が合っています。 しかし、その方針は、乱暴な抽象化による「副作用」があったのです。 副作用の1つを示します。 「宣言と使用の文法を一致させる方針」で考えると、 宣言文は int 型です。 しかし、その初期化子(初期値)はポインター型になって しまっていて、方針が崩れてしまっています。   void Func( int a )   {     int *p = &a; /* 変数 a のアドレスを代入、* はポインタ宣言を表す記号 */     *p = a; /* 変数 a に入っている値を代入、* は間接演算子 */   } 1行目も2行目も代入の左辺は *p ですが、1行目の右辺は変数のアドレス、 2行目の行の右辺は変数の値なのです。 文法上でも1行目の * はポインタ宣言子、 2行目の * は 間接参照演算子(間接演算子)と、異なります。 方針を貫くのであれば、 ポインター型の変数を宣言するときは、初期化子を禁止にしなければならなかったのですが、 対策は取られませんでした。 この対策をするルールも聞いたことがありません。 ちなみに、C++ 言語の参照型は、「宣言と使用の文法を一致させる方針」がとれません。 参照型の変数に &演算子(アドレス演算子)を付けられないからです。   int &p = a; /* 変数 a のアドレスを p に代入、& は参照型宣言を */ そもそも、変数を宣言しているのに、変数に演算子を付けたときのことを書いている のが紛らわしいのです。 何の話をしているの? ということです。 「*」の記号を型に 付ければ、ポインター型の変数を宣言するというそのままのことを書いていることになります。   void Func( int a )   {     int* p = &a; /* 変数 a のアドレスを代入、* はポインタ宣言を表す記号 */     *p = a; /* 変数 a に入っている値を代入、* は間接演算子 */   } 定義に基づいて教えたりルールを作ったほうがよいという考えは、正しくないケースも あります。 たとえば、1秒の定義です。 1956年に、「秒は、暦表時の1900年1月0日12時 に対する太陽年の 1/31556925.9747倍である」と定義されました。 細かい数字が 記されていて、いかにも正確そうです。 しかし、この定義よりももっと正確で扱いやすい 定義が見つかり、すぐに改定されます。 1967年に、「セシウム133 原子の基底状態の2つの 超微細準位間の遷移に対応する放射の 9192631770周期の継続時間」と定義されました。 (数字の細かさと正確さは関係なく、何か別のことに合わせているだけです。) 変数に * を付けることは、古い1秒の定義と同様に問題があり、変えるべき定義である ということです。 C言語では互換性を維持するために文法を変えることが難しいのですが、 C#では定義を変えることができました。 元の定義から変えてしまったことの問題があります。 それは、「うるう秒」が必要に なってしまったことです。 C言語のポインター型の宣言でいえば、定義と異なる記述に 変えてしまったことの問題は、1つの文でポインター型を複数宣言する書き方が できなくなってしまったことです。 C#言語のポインター型の宣言でいえば、同じ記述 でも、C言語と意味が異なるようになってしまったことです。 定義を変えても変えなくても、どちらにも問題はあるのですが、どちらの問題のほうが 大きいか、対策をしやすいのかを総合的に考えるべきなのです。 定義と異なるほうが 必ず大きな問題であるとは限らないのです。 初心者向けの教科書なら、多少の不正確さ があったとしても、分かりやすい(例:代入するときにも矛盾がない)ほうがいいに 決まっていますが、それすら分からない人もいるので困ったものです。 参考 ポインタ宣言の*記号、左寄せ派? 右寄せ派? http://togetter.com/li/185167 C言語でポインタ変数を意味する*(アスタリスク)について悩んだことがあります http://white-bear.info/archives/583 C言語のポインタがゼッタイにわかる本 (p120) https://books.google.co.jp/books?id=8UWCEazBU4wC&pg=PT125&lpg=PT125 1秒の定義 - NICT 情報通信研究機構 http://www2.nict.go.jp/aeri/sts/afs/One-Second.html 注目ニュース 一覧 ◇ 予約せずに即10へ。Windows 10インストール用のメディア作成ツール公開。 http://www.itmedia.co.jp/pcuser/articles/1507/29/news120.html … よくあるインストール メディアでバージョンアップ。 ◇ Windows 10 でただちに変更すべきこと。画像で見る8つの設定。 http://japan.cnet.com/news/service/35068033/ … せっかくなんで新機能を試してみたら? ◇ Windows 10で Edge をデフォルトブラウザにしたMicrosoftにMozillaが苦言。 http://www.itmedia.co.jp/news/articles/1507/31/news063.html … 人気がないから独禁法違反にはならなそう。 ◇ Androidに極めて深刻な脆弱性、MMSで端末制御可能に。 http://www.itmedia.co.jp/enterprise/articles/1507/28/news049.html … google も、さすがにすぐにパッチを提供した。 ◇ Android に新たな脆弱性、端末が操作不能になる恐れ。 http://japan.cnet.com/news/service/35068118/ … こちらは対応しないのか。 ◇ 命縮めた天才、任天堂・岩田社長、対ソニーで屈辱味わい、円高の不運に泣く。 http://www.itmedia.co.jp/news/articles/1507/28/news052.html … プログラマーとしては屈辱的な選択だったかもしれない。 ◇ Twitterがパクツイ規制に本腰? 盗用ツイートを次々と強制書き換えか。 http://www.itmedia.co.jp/news/articles/1507/27/news083.html … ちゃんと掲載料を払え。 ◇ インテルとマイクロン、新メモリ技術 3D XPoint を発表。 http://japan.cnet.com/news/service/35068050/ … 現在のフラッシュ メモリーや SSD より1000倍高速。 ◇ パスワードは時代遅れです。Windows Hello と FIDO を理解する。 http://www.itmedia.co.jp/enterprise/articles/1507/29/news036.html … パスワードより PIN コードのほうがセキュアな理由。 ◇ 漫画家の赤松健氏とGYAOがタッグ、ヤフー傘下で マンガ図書館Z がスタート。 http://internet.watch.impress.co.jp/docs/news/20150803_714806.html … ヤフーのメリットは企業イメージか。 ソフトウェアデザイン館 Sage Plaisir 21 ホームページ >>> http://www.sage-p.com/ メルマガ >>> http://www.mag2.com/m/0000083983.html ブログ >>> http://blog.livedoor.jp/sage_p/ ツイッター >>> http://twitter.com/Ts_Neko ダウンロード >>> http://www.sage-p.com/freesoft.htm サポート掲示板 >>> http://www.sage-p.com/kg_ban09/z6037C8.cgi 東日本大震災 >>> http://www.sage-p.com/saigai.html メール >>> ts-neko◇sage-p.com ←◇を@に変えてください 緊急メールは件名に「うどんメール」を付けてください。 このメルマガの登録・解除 - http://www.mag2.com/m/0000083983.htm