C言語関係掲示板

過去ログ

No.83.構造体への代入


ファイル又はDBなどから読み込んだchar data[3000]
というデータ項目があったとします。これを構造体に
代入して構造体のメンバーを参照したいのですが
どのようにすればよいでしょうか
構造体のメンバーは全てchar型ですが、100個以上の
メンバー数です。

char data[3000];

struct in {
char aa[20];
char bb[8];
       ・
       ・
char zz[12];
} pr_d;

dataをpr_dに代入出来ないし、どのようにしたらdataの
内容を、pr_d.aaなどと参照出来るようになるのでしょうか


一番簡単なのはこれでしょうか。
        memcpy(&pr_d, data, sizeof(pr_d));
うちではうまくいきましたが、構造体メンバの並び順が処理系依存だった気がしないでもないので自信ないです。

他には下記のようにテーブルを持つとループで楽にコピーできそうです。
データ構造に変更があっても比較的楽に対応できそうですし。
私の頭ではこのあたりが限界です。

const struct {
        void *dst; void *src; size_t size;
} cpy_tbl[] = {
        { pr_d.aa, data + 0,  sizeof(pr_d.aa) },
        { pr_d.bb, data + 20, sizeof(pr_d.bb) },
        ...
        { pr_d.zz, data + ??, sizeof(pr_d.zz) },
};

        for ( i = 0; i < sizeof(cpy_tbl) / sizeof(cpy_tbl[0]); i++ )
                memcpy(cpy_tbl[i].dst, cpy_tbl[i].src, cpy_tbl[i].size);

的外れな回答してたらごめんなさい。


ども。


>一番簡単なのはこれでしょうか。
        memcpy(&pr_d, data, sizeof(pr_d));

>うちではうまくいきましたが、構造体メンバの並び順が処理系依存だった気がしないでもないので自信ないです。

構造体メンバの並び順はだいじょぶです。今回のような問題で気にしなければ
ならないのは、エンディアンとパディングですね。でも今回は全部char[]だから
エンディアンは関係ないし、charしかないのに(バイトアクセスなのに)なんらか
のアラインメントをとる処理系もおそらくないので、今回は上記の方法で
よいかと。

ちなみに。
data[]がstruct inのメモリマッピングと同一で、エンディアンとパディングを
気にしなくていいという条件ならば、dataを(struct in*)型にキャストして
ポインタで扱うという強引な方法もあります。コピーが不要で、直接(読み)書き
してもよく、かつ、速度が要求され、メモリに制限がある場合は検討してみて
ください。でも、強引な方法であることをわすれないように(もちろん使える
条件も注意)。


メンバのメモリマッピングを意識せずに、外部(ファイルやDBなど)のデータを
構造体に読み込む一般的な方法は多分ありません。一般的には、めんどくさい
ですがひとつひとつ処理するしかないです。今回のように全部char[]という
ような(例外的な)条件があれば、(例外的に)少しはましな方法もありますが。


それにしても100以上もメンバがある場合はちょっと人間の手で扱うには厳しい
ものがありますね。いろいろな事情でどーしても扱わなければならない場面も
あるんでしょうけど。可能ならば早いうちに機械的に扱えるような何かよい方法
を考えた方がよいかと。。


では。


いつもフォローありがとうございます。
ほんと、勉強なります。

> 気にしなくていいという条件ならば、dataを(struct in*)型にキャストして

すっかり忘れてました。
マイコンのレジスタを扱うとき、ビットフィールドと組み合わせてえらい重宝した記憶があります。
これ便利ですよね。
初めて知ったときはビビりました。


chu-さんkikkさん。有り難うございました。
不慣れな者でchu-さん宛のものを、kikkさん宛に出してしまいました。
お詫びいたします。
kikkさんの「dataを(struct in*)型にキャストしてポインタで扱うという
強引な方法もあります。」という案は、「dataをstruct inにかぶせる」
ということの逆の発想のように感じました。これも今後の課題とさせていただきたいと思います。


早速の解答を頂きまして有り難うございます。

><PRE>一番簡単なのはこれでしょうか。
memcpy(&pr_d, data, sizeof(pr_d));

memcpy(&pr_d, data, sizeof(pr_d)); で上手くいきました。
初心者用の講座とか、入門書のたぐいにはこのmemcpy関数が
載っていないようで(私が接している環境のみか?)こんなのが
あったのかという気持ちです。

「テーブルを持ってループ処理」については引き続き今後の検討課題
とさせて下さい。

本当に有り難うございました。

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.01.11
Copyright(c) 2000-2002 TOMOJI All Rights Reserved