ページ 11

構造体

Posted: 2008年12月09日(火) 19:59
by ざこ
#include <stdio.h>

int main(void)
{

  FILE *file;
  long buf;
  unsigned char buf1[40];
  unsigned char buf2;
  short buf3;
  double buf4;
  short n;

  file=fopen("ファイル名"."rb");
  fread(&buf,sizeof(long),1,file);
  printf("図面%0x\n",buf);

  fread(&buf2,sizeof(char),1,file);
  printf("ファイル%0x\n",buf2);

  fread(&buf2,sizeof(char),1,file);

  fread(&buf3,sizeof(short),1,file);
  printf("ver%0x\n",buf3);

  fread(&n,sizeof(short),1,file);
  printf("要素数%0x\n",n);

  fread(&buf3,sizeof(short),1,file);
  printf("type%0x\n",buf3);

  fread(&buf4,sizeof(double),1,file);
  printf("始点x%7.3f\n",buf4);

  fread(&buf4,sizeof(double),1,file);
  printf("始点y%7.3f\n",buf4);

  fread(&buf4,sizeof(double),1,file);
  printf("終点x%7.3f\n",buf4);

 fread(&buf4,sizeof(double),1,file);
  printf("終点y%7.3f\n",buf4);

  fread(buf1,sizeof(char),32,file);
  fread(&buf3,sizeof(short),1,file);
  printf("最大%0x\n",buf3);

  fclose(file);

  return 0;
}

これを構造体を使って書き直すとどうなるのでしょうか?
私の考えは・・

typedef struct{
long num;
  char fl;
  char res;
  short ver;
  short no;
  short type;
  double d[4];
  char res2[32];
  short resc;
}pftest;

int main(void)
{
  FILE *file;
  pftest ts;

  file=fopen("ファイル名","rb");
  fread(&ts,sizeof(ts),1,file);
   
  printf("図面%0x\n",ts.num);
  printf("ファイル%0x\n",ts.fl);
  printf("ver%0x\n",ts.ver);
  printf("要素数%0x\n",ts.no);
  printf("type:%0x\n",ts.type);
  printf("始点X%7.3f\n",ts.d[0]);
  printf("始点Y%7.3f\n",ts.d[1]);
  printf("終点X%7.3f\n",ts.d[2]);
  printf("終点Y%7.3f\n",ts.d[3]);

  prtinf("max%0x\n",ts.rec);
  fclose(file);
 
  return 0;
}
としてみたのですがエラーはでませんが正常に動きません。
問題が発生した為にこのプログラムを終了します とでます。
どうすればいいのでしょうか

Re:構造体

Posted: 2008年12月09日(火) 20:27
by box
> としてみたのですがエラーはでませんが

そうですか?

>   prtinf("max%0x\n",ts.rec);

少なくとも、ここでコンパイルエラーが出ます。printfの綴りが違っています。
もし、お手元にあるソースコードではコンパイルエラーが出ないのであれば、
そのソースコードをそっくりそのままコピー&ペーストしてください。

>   file=fopen("ファイル名","rb");

「ファイル名」という名前のファイルが存在していますか?
fopen()の戻り値がNULLかどうか(ファイルのオープンが失敗したか成功したか)を
必ずチェックしてください。

Re:構造体

Posted: 2008年12月09日(火) 20:39
by non
間違っているかも知れませんが、私の記憶によると、(処理系に依存すると思うけど)
4の倍数でメモリが確保されたと思います。
longは4バイトですが、次のcharは1バイトが2個で2バイト、この後に2バイトの空きが出来て、
shortは2バイトですが、次のshortとの間に2バイトの空きが出来る。
それで、連続して先頭から読み込んでも、間に隙間があるので、うまくいかないのでは。
もしくは、用意したファイルのバイト数と異なっているのでは?

Re:構造体

Posted: 2008年12月09日(火) 21:39
by ざこ
ああほとんどコピペなんですが所々変えてるので(もっと長い文だったのですが短縮とか変更とかいろいろ)
無駄に長かったので見やすくする為変更してるんですが・・間違ったらもともこもないですね・・
以後気をつけます。

Re:構造体

Posted: 2008年12月09日(火) 21:43
by ざこ
上のほうのプログラムだとうまくいって下の方のプログラムだとうまくいかないんです。
構造体の使い方が間違ってると思うのですが、どうでしょうか。

Re:構造体

Posted: 2008年12月09日(火) 22:10
by non
私の意見はスルーですか。
調べるから、データをください。バイナリーエディタもダウンロードしたし。

Re:構造体

Posted: 2008年12月09日(火) 22:26
by box
> 上のほうのプログラムだとうまくいって下の方のプログラムだとうまくいかないんです。

「ファイル名」という名前のファイルがありますか?
fopen()の戻り値をチェックしていますか?

Re:構造体

Posted: 2008年12月09日(火) 22:26
by GPGA
「アラインメント」で検索しましょう。

Re:構造体

Posted: 2008年12月09日(火) 23:14
by ざこ
>nonさん
そういうつもりではないんです。私の質問は上のプログラムは正常に稼動します。しかし下のプログラム、
つまり上のプログラムを構造体を使って書くと間違いなので構造体の使い方が間違ってるのかどうか
聞きたかったのです。だからcharとかshortとかの使い方はあっているはずです。

>boxさん
ファイル名の所はファイル名が入っているということです。
戻り値はまだ調べてなかったです。今試せる環境にいないので明日調べます。

>GPGA
ネットはできますので早速調べて見ます。ありがとうございました。

Re:構造体

Posted: 2008年12月10日(水) 00:27
by たかぎ
処理系不明なので正確なことはわかりませんが...

元のソース構造体を用いたソースも、動作が未定義になる箇所があります。
それ以外のことについては何ともいえません。

> boxさん
> prtinf("max%0x\n",ts.rec);
> 少なくとも、ここでコンパイルエラーが出ます。

リンクエラーにはなるかもしれませんが、コンパイルエラーにはなりませんね。
# 広義のコンパイルエラーですが...。

Re:構造体

Posted: 2008年12月10日(水) 00:44
by lbfuvab
nonさんの言ってる事が多分正しいのにまともに取り合わないとは良い根性してますねwwww

Re:構造体

Posted: 2008年12月10日(水) 01:12
by レッツ
まず「何がしたいのか」を文頭に書かないと何がしたいのか意味がわかりづらいです。

Re:構造体

Posted: 2008年12月10日(水) 04:29
by GPGA
>lbfuvabさん
nonさんには失礼かもしれないですが、初心者がnonさんの文章読んでも
その内容が、構造体の中のデータ並びのことを指しているとは気付きにくいと思います。

内容が理解できていれば、No:25442のnonさんに対する
ざこさんの返答は、あのような文章にはならないのではないでしょうか?


>ざこさん
検索ですが、「アラインメント」だとCPUのほうの説明が出てきますね。(まぁ、本来はこっちが正しいのですが)
「構造体 アラインメント」で検索してみてください。

Re:構造体

Posted: 2008年12月10日(水) 07:53
by toyo
構造体にすると各変数の間に隙間が出来たりします。
そのため構造体にそのままファイルを読み込むには注意が必要です。
構造体の隙間をなくす方法もありますがコンパイラによって違います。
VisualC++の場合は構造体定義の部分を
#pragma pack(push,1)
typedef struct{
    long num;
    char fl;
    char res;
    short ver;
    short no;
    short type;
    double d[4];
    char res2[32];
   short resc;
}pftest;
#pragma pack(pop)
のようにするとうまくいくと思います。

Re:構造体

Posted: 2008年12月10日(水) 09:58
by ざこ
成る程、アライメントの事は初めて知りました。丁寧な解説ありがとうございます、GPGAさん,tuyuさん。
上記の#pragmaの部分を入れてみても変わらなかったです。デバッグで調べてみると

fread(&ts,sizeof(ts),1,file);

ここから先が通らないですね。やはりアライメントが問題なような気もしますが、うーん。
ちなみにVC++6.0使っています。

Re:構造体

Posted: 2008年12月10日(水) 10:03
by Mist
nonさんの指摘であっていると思いますが
printf("%d\n", sizeof(ts));
として、tsのサイズがどれだけになっているか調べられてみてはどうですか。

あと、「C言語 アライメント」、「C言語 パディング」でググってください。
パディングのなくし方は処理系に依存しますので、実行環境(OS)、開発環境(コンパイラ)を明記してください。

Re:構造体

Posted: 2008年12月10日(水) 10:11
by たかぎ
> printf("%d\n", sizeof(ts));

VC++6.0なら問題ないとは思いますが、上の記述は未定義の動作につながります。
printf("%d\n", (int)sizeof(ts));
↑のようにしてやる必要があります。

Re:構造体

Posted: 2008年12月10日(水) 10:16
by ざこ
上から順に見ていくとfread(&ts,sizeof(ts),1,file); でやはりとまります。
ハンドルされていない例外は・・ と出ます。
fread(&ts,sizeof(ts),1,file); ここにブレイクポイント入れてデバッグしてsizeof(ts)の中身を
調べました所、78となっておりピタリです。

そしてその文の下の文つまり printf("図面%0x\n",ts.num); にブレイクポイントを変更してデバッグすると
ハンドルされていない例外は・・と出てとまります。

fread(&ts,sizeof(ts),1,file); → printf("図面%0x\n",ts.num); この間で止まるようです。
OSはwindowsXP 開発環境はVC++6.0です。

Re:構造体

Posted: 2008年12月10日(水) 10:24
by 御津凪
> ハンドルされていない例外は・・ と出ます。

ファイルが開けていないとかいうオチじゃないでしょうか。
fread のところでブレイクポイントをつけて、
file の値が NULL (または0)になっていないか確認してください。

あと、アラインメント問題には直接関係しませんが、

fread(&ts,sizeof(ts),1,file);

を、

fread(&ts,1,(int)sizeof(ts),file);

としても読み込めるので、試してみてはどうでしょうか。

Re:構造体

Posted: 2008年12月10日(水) 10:30
by Mist
freadの戻り値をチェックしてみては。
正常にリードできているのであれば1になっていると思いますが。

Re:構造体

Posted: 2008年12月10日(水) 10:34
by ざこ
すいません、なんかファイルはちゃんと開けてたみたいなんですがそのファイルがおかしかったようです。
別のファイルだとちゃんと動きました。壊れてたのかどうかわかりませんが、とりあえず解決しました。
ありがとうございました。

Re:構造体

Posted: 2008年12月10日(水) 10:35
by Dixq (管理人)
もしかして拡張子を表示しない設定にしているとか・・?
その場合、ファイル名には拡張子も書かないといけないので、ファイル名を指定する文字列は「ファイル名.dat」とかにしないといけません。
もし設定していない時はwindowsならフォルダオプションで表示するように変えられます。