̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ IT ニュース&コラム 2014/ 3/17 通巻657号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ アドレスやポインターを配列にするな - リーダブル・コード(20) 音声データのようなデジタル データがどのようになっているかは、相対アドレス (オフセット)によって定義されています。 たとえば、下記のように、データの 先頭が相対アドレスの基準(相対アドレス=0x00)としたら、データの長さが 相対アドレス 0x04 にあって、データの並びが相対アドレス 0x08 から並んでいる といったような感じです。 JPEG や MPEG などのバイナリーファイルもこのような 相対アドレスによって定義されています。 Addr Size Description -------------------------------- 0x00 0x04 データの種類 0x04 0x04 データXの長さ(バイト数) 0x08 0x02 データX[0] 0x0A 0x02 データX[1] 0x0C 0x02 データX[2]  :   : Y+0x00 0x04 データYの長さ(バイト数) Y+0x04 0x02 データY[0] Y+0x06 0x02 データY[1]  :   : バイナリー データをファイルから読み込んで、下記の配列に入っていたとします。 uint8_t data[ 0x100 ]; データの長さは、次のようにすれば取得できます。 data 配列の 0x04 番目から 4バイトの整数型(uint32_t)としてリードします(エンディアンの変換が 不要な場合)。 uint32_t x_length = *(uint32_t*) &data[ 0x04 ]; これを、ポインター形式(アドレス形式)で書くと次のようになります。 data 配列の先頭アドレスから +0x04 したアドレスから、4バイトの整数型(uint32_t) としてリードします。 uint32_t x_length = *(uint32_t*)( data + 0x04 ); 前者(配列形式)と後者(アドレス形式)のどちらが読みやすいでしょうか。 data 配列があるという前提を考えるなら、前者の方が読みやすいでしょう。 こうして、後者のようなアドレス形式(ポインター演算)の表現を禁止して、 前者に統一しましょうというコーディング ルールができあがります。 では、応用編です。 データY[1] を取得するコードは、配列形式では、 uint32_t x_length = *(uint32_t*) &data[ 0x04 ]; int16_t* array_of_X = (int16_t*) &data[ 0x08 ]; uint32_t offset_to_Y = &array_of_X[ x_length / 2 ]; int16_t* array_of_Y = (int16_t*) &data[ offset_to_Y + 0x04 ]; data_Y_1 = array_of_Y[ 1 ]; アドレス形式では、 uint32_t x_length = *(uint32_t*)( data + 0x04 ); int16_t* array_of_Y = (int16_t*)( data + 0x08 + x_length + 0x04 ); data_Y_1 = array_of_Y[ 1 ]; となります。 どちらが分かりやすいでしょうか。 前者は、data 配列とオフセットの2つを意識しなければなりませんが、 後者はアドレスだけを意識するだけでよくなります。 つまり、読みやすいのです。 そもそも前者はコードの量が多いから読みにくくなっているのであって、 その原因である array_of_X 変数と offset_to_Y 変数を作るのは不公平だ、 と考えるかも知れません。 しかし、前者は、array_of_X 変数と offset_to_Y 変数を経由しなければなりません。 なぜなら、ポインターを使わないということは、 アドレスという概念を使って表現してはいけないからです。 そんな難しいことは考えずに、array_of_X 変数と offset_to_Y 変数がなくても よいと考えるなら、 int16_t* array_of_Y = (int16_t*) &data[ 0x08 + x_length + 0x04 ]; となり、後者とほとんど変わらないと思うかもしれません。 しかし、これでも、 読むときは全然違います。 なぜなら、演算子の優先順位から、data[ 0x08 + ... ] は、data[ 0x08 ] とは違うものとして、0x08 を先に読んでしまうからです。 そして、0x08 って何? となるわけです。 0x08 + ... は、オフセットなん だろうけど、その一部である 0x08 はオフセットと考えてよい確証がなく なっているのです。 読みにくいどころか、確証をもって読めないのです。 data + 0x08 + x_length + 0x04 は、data(配列の先頭アドレス)を出発点と して、+ 0x08 して + x_length して + 0x04 するというように、統一した 読み方ができます。 この考えができるのも、アドレスの次元で計算を考えて いるからこそです。 しかも、演算子の優先順位から 0x08 + x_length より data + 0x08 が先に計算され、それは「データXの長さ」が入った変数のアドレス であると確証が持てます。 そもそも、バイナリー形式のデータの資料には、 アドレスで書いてあるのに、わざわざ配列に置き換えてしまうのは、余計な ことなのです。 もし、&data[ 0x08 + x_length + 0x04 ] と書かれていたら、 配列(ポインター)の型に注意しながら、data + 0x08 + x_length + 0x04 に 式を変換して、初めて資料と照らし合わせることができます。 ポインターに対する加減算を禁止するコーディング ルールができる大きな要因は、 1バイト以外の整数や構造体へのポインターの加減算が +1 単位では ないことです。 これは、おそらくポインターをアドレスではなく、配列の インデックス(配列番号)として考えて C言語の仕様を決めてしまったのだろうと 思いますが、確かにこれはポインターの型を注意しなければならないため、 ややこしいです。 ですから、ポインターに対する加減算を禁止するのではなく、 1バイト以外の整数へのポインターに対する加減算を禁止すればよいのです。 もしくは、uintptr_t 型にキャストしてから計算すればよいのです。 ただ、 そのキャストを禁止するルールもあるから厄介です。 上記の配列形式で使われて いるポインター型のキャストを禁止するルールもあります。 バイナリー データをよく扱うのは、組込み系です。 しかし、こういったルールが、 組込み系のコーディング ルールとして存在するのですから不思議なことです。 参考: 組込みソフトウェア開発向けコーディング作法ガイド - IPA http://www.ipa.go.jp/sec/publish/tn06-004.html R1.3.1 ポインタの指す範囲に気を付ける R2.7.1 ポインター型と整数型の間で変換してはならない 注目ニュース 一覧 ◇ アップル CarPlay を使ってみた。メルセデス・ベンツ搭載版の第一印象。 http://japan.cnet.com/news/commentary/35044821/ http://japan.cnet.com/news/service/35044719/ … ホーム ボタン+アイコンという組み合わせが iOS。 ◇ ソニーとパナソニック、業務用の次世代光ディスク規格 Archival Disc 策定。 http://www.itmedia.co.jp/lifestyle/articles/1403/10/news135.html … コンパクトに保存。まずは、BD の 6倍の容量を目指す。 ◇ 東京新聞ビットコイン課税、政府公式見解、通貨でない。 http://www.tokyo-np.co.jp/article/economics/news/CK2014030502000234.html … 通貨ではないが、通貨なら課税対象となる取引もある。 ◇ Bitcoin創設者とされる中本哲史氏、米在住64歳男性か。 http://japan.cnet.com/news/society/35044907/ … 理論の開発者と実際に商売をする人は分けるべき。 ◇ 遊んでわかったPS4の本当にステキな10のポイント。 http://game.watch.impress.co.jp/docs/news/20140228_637376.html … PS3では、ゲーム画面はフルHDになっていなかった。 ◇ RDPとRemoteFXのお話。 http://www.atmarkit.co.jp/ait/articles/1403/12/news017.html … 画面共有だけじゃない。ネットワークや USB もリモート。 ◇ ネットの 全文ネタバレ に出版社が断固たる措置? http://www.itmedia.co.jp/news/articles/1403/06/news061.html … パクリ商売に断固たる措置。 ◇ iOS 7.1、アプリ内課金時に警告表示。子どもの課金問題に対処。 http://japan.cnet.com/news/service/35045161/ … 一度認証したら一定時間認証しなくてもよいという考えを改めなければ。 ◇ Firefoxが段階的にプラグインを廃止すると発表。 http://weekly.ascii.jp/elem/000/000/204/204679/ … アドオンは廃止の対象外。 ソフトウェアデザイン館 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