- PR -

C言語の構造体を配列の様に見る事は可能?

投稿者投稿内容
はにまる
ぬし
会議室デビュー日: 2003/12/19
投稿数: 969
お住まい・勤務地: 誤字脱字の国
投稿日時: 2004-08-22 23:30
はにまるです。

okutinさん、jittaさんご返答ありがとうございます。
勉強になります。コンパイル周りはmakefileの構文だけで充分かと思っていましたが
ccのオプションも一通り目を通していた方が宜しいですね。 sweat:
まいるどきゃっと
大ベテラン
会議室デビュー日: 2004/08/12
投稿数: 135
お住まい・勤務地: 群馬
投稿日時: 2004-08-25 10:34
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=13934&forum=7
まいるどきゃっとです。こんにちは。
返事が遅くなりました。

引用:

引用:

まいるどきゃっとさんの投稿より:

(1) 後からソースを見た人にとって、何を意図した数字か分かりにくい。
(2) 必要な長さと8バイト単位の長さの2重管理になってしまう。
(3) Cコンパイラの実装にとらわれた考え方に基づいている。
(4) そもそも、8バイト単位にする意味が思いつかなかった。


1→文字列の終端まで含めて、宣言します。配列宣言で+1とかはしません。
2→よって、2重管理になるとは思いません。
3→もちろん、コンパイラの実装によって異なります。
4→8バイトではなく、「最小単位」です。



あ、すみません。
とりあえず先の私の投稿の「8バイト単位」は「最小単位」と読み替えてください。

文字列の終端まで含めたサイズを定数として宣言するとの事ですが、

enum {
BOOK_TITLE_MAX = 40, /* 書名の最大長 */
BOOK_TITLE_ARRAY_SIZE = (40 + 8), /* 書名を格納する配列のサイズ */
}

というように定数宣言したとしても、なぜ最大長+8なのかという疑問が浮ぶことには違いないわけです。

+1で済むところを+8にしているのは、単に領域を余分に取っているのか、それとも何か別の意味があるのか、そもそも本当に書名を格納する配列宣言用の定数なのか判断がつきません。
ソースを一通り解析してみてやっと、「あ、単に余分に領域を取っているだけか」と(間違った)結論がだせます。
これが最大長+1なら、それはCの慣習上ナル文字分であり、書名を格納する配列宣言用の定数だと容易に想像できます(あ、もちろんきちんと裏はとりますが)。

また、書名の最大長を変更する必要が出た場合、たとえば書名の最大長が50に変更になったとします。
影響範囲を調査するには全ソースに対して40と41でgrepすれば済みますが、さらに48でもする必要があります。バイト境界を意識した数字は切りがいいので、全然関係ないソースがより引っかかりやすくなります。その分、調査の手間が増えます。
そして、配列のサイズは51と56と58のどれが適切なのかソースを書いた人間にしかわかりません。

定数に求められるのは、用途がわかりやすいこと、適切な値が設定されていることです。
最小単位で宣言された定数は、あとからソースを読むことになった人にとっては面倒な存在になります。
私がバイト境界を意識して書いたソースをメンテナンスすることになった人達には、「なぜわざわざ分かりにくくするの?」と非常に不評でした。

(2)では、最大長が40文字と決められた書名の場合だと、

enum {
BOOK_TITLE_MAX = 40, /* 書名の最大長 */
BOOK_TITLE_ARRAY_SIZE = (40 + 1), /* 書名を格納する配列のサイズ */
BOOK_TITLE_STRUCT_ARRAY_SIZE = (40 + 8), /* 書名を格納する配列のサイズ(構造体向け) */
}

となるのを嫌ったんですが、そういえば上から2番目の定数を使わずに1番目と3番目だけ使用してコーディングする手もあるか、ということにいまさら気づきました。
というわけで、申し訳ありませんが(2)はなかったことにしてください。

引用:

char 3バイト
int
char 4バイト
と書いてあると、実際のバイト数と異なります。しかし、バイト境界を意識して設計することで、そのような食い違いによるバグを作り込む可能性が減ります。



バイト境界を意識した設計で減らせるバグってちょっと思いつかないのですが、どんな感じでしょうか?


[ メッセージ編集済み 編集者: まいるどきゃっと 編集日時 2004-08-25 10:35 ]
okutin
ベテラン
会議室デビュー日: 2003/12/11
投稿数: 98
お住まい・勤務地: 広島
投稿日時: 2004-08-25 10:50
こんにちは。

引用:

まいるどきゃっとさんの書き込み (2004-08-25 10:34) より:

バイト境界を意識した設計で減らせるバグってちょっと思いつかないのですが、どんな感じでしょうか?




現在、このバグと格闘中であります。
方やCで書かれたレガシーシステムで、方や新規のJavaなWebシステム。
この二つの間をソケットを使って通信しているのですが、
Javaな人「通信データの仕様書をください」
Cな人「以下の通りです」
char data1[3];
int data2;
Javaな人「仕様書どおりに送ったよ」
Cな人「なんかdata2が1バイトずれてるんですけど・・・」
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-08-25 11:55
引用:

まいるどきゃっとさんの書き込み (2004-08-25 10:34) より:

文字列の終端まで含めたサイズを定数として宣言するとの事ですが、

enum {
BOOK_TITLE_MAX = 40, /* 書名の最大長 */
BOOK_TITLE_ARRAY_SIZE = (40 + 8 ), /* 書名を格納する配列のサイズ */
}

というように定数宣言したとしても、なぜ最大長+8なのかという疑問が浮ぶことには違いないわけです。


 いえ、BOOK_TITLE_MAXを、48と宣言します。そして、入力時に40文字に制限します。
 とはいえ、外部に入出力する構造体の中で使う場合に意味があることであって、単独で使用する分にはまったく意味のないことです。

ちげ〜
 BOOK_TITLE_MAXは40で、40文字まで入力できますが、strcpyを使わずに、strncpyでバイト数を指定する、、、です。あくまでも構造体の中の話しです。

引用:

また、書名の最大長を変更する必要が出た場合、たとえば書名の最大長が50に変更になったとします。


 それは別の問題では?マジックナンバー(コード中に直接書き込まれた数値)を無くすことが、EnumやDefineで定義する意義だったはずでは?また、定数の宣言はヘッダなどの一カ所にまとめるべきでは?・・・と、『プログラミング作法』にも書いてあったと思います。


引用:

定数に求められるのは、用途がわかりやすいこと、適切な値が設定されていることです。
最小単位で宣言された定数は、あとからソースを読むことになった人にとっては面倒な存在になります。
私がバイト境界を意識して書いたソースをメンテナンスすることになった人達には、「なぜわざわざ分かりにくくするの?」と非常に不評でした。


 わかりやすさを優先して、バグを作り込むことは許されません。しかし、これはどのようなシステムを作っているかという文化によるものなのでしょう。私がいたところでは、他システムとの連携が多かったので、入出力ファイルについて、バイナリエディタでチェックしていました。自分で書いて自分で読むのなら、特に意識する必要はないでしょう。しかし、他人に読ませなければならない為、仕様書と実際がずれてはいけなかったのです。なので、なぜバイト境界をあわせることが「わかりにくい」のか、理解が難しい
 なお、他システムの入出力では、書くときは構造体をwriteしても、読むときはchar[]バッファにためて1バイトずつ移動させるということをしていました。それほど、他システムとの連携では、注意を払わなければならないところでした。



バイト境界について説明したページ:「バイト境界」でGoogle。1ページ目から拾い読み
http://docs.hp.com/ja/B3906-90007/ch07s08.html
http://www.int21.co.jp/pcdn/magazine/mado/vbt9001/vbt9001.html

[ メッセージ編集済み 編集者: Jitta 編集日時 2004-08-25 13:11 ]
okutin
ベテラン
会議室デビュー日: 2003/12/11
投稿数: 98
お住まい・勤務地: 広島
投稿日時: 2004-08-25 12:54
こんにちは。

無駄な領域といえば・・・
バイト境界の明示的な調整はメインフレームでは当たり前のことで、新人教育の時点で徹底されていたのですが、パッチ用領域の確保もありましたね。
トラブル時にソースを修正してコンパイルしてインストールしてなどと悠長なことはやってられないので、パッチ用領域に直接機械語のパッチを書き込んで、そこにジャンプするようにしてパッチを有効化したりとか。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-08-25 13:28
構造体の宣言でアラインメントに合あわすかどうかって、場合によりません?
他との構造体データのやり取りがある場合に、そのやり取りの仕様絡みで決めることだと思います。
その際に、構造体の宣言自体のサイズをあわせる必要があるとか、合わせておくことにしたというのであれば、そういうルールとしてそのように宣言しますし、特に何もなければアラインメント調整はしないです。

※他とのやり取りの中で、そのアラインメントをどうするか、あるいはそもそもアラインメントに依存するようなやり取りを行うのかによって、どうするべきかが変わってくるからです。

特にそれらが想定されない中で、例えば8バイト境界に合わせることにはあまり意味がないと思います。個人的には意味が分かりにくくなるのでやりたくないです。
先のことを想定して、念のため8バイト単位にしておこうと決めることはあるかもしれませんが、いつでもそうするべきとは思いません。

他とのやり取り等がない状態でアラインメントに依存するようなプログラムがあったとしたら、普通そういうプログラム自体が問題でしょうし。

※アラインメントという概念自体を意識したり理解する必要がないといっているわけではありません。
skulker
ベテラン
会議室デビュー日: 2004/06/08
投稿数: 67
投稿日時: 2004-08-25 14:34
そもそも、Cの仕様の範囲内で構造体のメンバのアラインメントってできましたっけ。
結局、処理系依存のhackでしかないんじゃなかったでした?

ひとつの処理系を使い続けて、かつその処理系の動きが変化しないと保証されているのであればいいですけど、あまりお行儀のいいプログラミングではないと思います。
えムナウ
大ベテラン
会議室デビュー日: 2004/06/10
投稿数: 187
お住まい・勤務地: 東京
投稿日時: 2004-08-26 01:08
他とのやり取りの無い局面ではアライメントはあわせる必要は無いと思います。

逆にアライメントを合わせて他とのやり取りを考慮するのであれば、
short/int のバイト順や、浮動小数点の内部形式、文字コードページのエンコーディング も考慮すべきだと思います。
当然その前に交換形式の検討から入るべきでしょうが・・・
つまり対象となる相手があって初めて考慮できる要素でもあります。
#あらかじめ何もしない変換関数を用意しておいて「将来のために考慮しておきましたよ」ということも出来ますが。

ちなみに「漢字イン」と「漢字アウト」を使用するJISコードに変換する可能性もありえます。

_________________
えムナウ Microsoft MVP for Visual Developer - C#,2005/01-2007/12
えムナウのプログラミングのページ Blog1 Blog2

スキルアップ/キャリアアップ(JOB@IT)