質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Q&A

解決済

2回答

4519閲覧

C言語でバイナリモードでファイルにデータを保存して、そのファイルを開いたときに、どういう理屈でその内容で保存されているのでしょうか?

tada_tadaa

総合スコア110

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

0グッド

0クリップ

投稿2016/02/03 12:29

C言語を学習しています。で、少し気になったというか興味
がわいたことがありまして、それは、C言語で数値や文字を
ファイルに保存するのですが、アスキーモードで保存した
時は、保存したファイルを開いても中身が保存したときと、
同じで読めるのですが、バイナリモードで保存したときは、
保存したファイルを開いても、変な文字になっているのです。
例えば下記にC言語のソースを載せます。

c

1#include <stdio.h> 2#include <stdlib.h> 3 4int main(void) 5{ 6 FILE *fp; 7 int i; 8 int i2 = 0; 9 10 /* 書き込みのためにファイルを開く */ 11 if((fp = fopen("myfile", "wb"))==NULL) { 12 printf("ファイルを開くことができません\n"); 13 exit(1); 14 } 15 16 i = 10; 17 18 if(fwrite(&i, 2, 1, fp) != 1){ 19 printf("書き込みエラーが起こりました\n"); 20 exit(1); 21 } 22 fclose(fp); 23 24 /* 読み込みのためにファイルを開く */ 25 if((fp = fopen("myfile", "rb"))==NULL) { 26 printf("ファイルを開くことができません2\n"); 27 exit(1); 28 } 29 30 if(fread(&i2, 2, 1, fp) != 1) { 31 printf("読み込みエラーが起こりました\n"); 32 exit(1); 33 } 34 printf("i2は %d です", i2); 35 fclose(fp); 36 37 return 0; 38}

で、結果は
i2は 10 です
と、表示されます。
しかし、ファイルを(myfile)開いてみると、改行と半角
スペースがあるだけです。さらに i の値を1000にして
実行してみて、ファイルを秀丸エディタのバイナリモード
で開いてみると
E8,03,
という記述になっています。
そこで思ったのですがこれはどういう理屈で
E8,03,になったのだろうかと少し気になりましたので
質問させていただきました。
どなたかお分かりの方がいれば教えてもらえればと思います。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

さらに i の値を1000にして実行してみて、ファイルを秀丸エディタのバイナリモードで開いてみると
E8,03,
という記述になっています。

Windowsの電卓のプログラマモード等を使って計算すると分かりますが、10進数の1000を16進数で表現すると000003E8となります。
そして、PCのCPUはリトルエンディアンでデータを保存しますので、下位バイト→上位バイトの順で並びます。000003E8ならE8 03 00 00と記録されるのです。
だから、E8, 03,00,00となります。(後ろに2つ00が続いていた筈です。)

同様に最初に保存した10は16進数で0000000Aですので、秀丸エディタのバイナリ・モードで開くと、0A,00,00,00となっている筈です。

fwrite等を使ってバイナリのまま保存すると上記のようになり、通常のテキスト・エディタでは読めない場合が多いです。
fprintf等を使って文字へ変換して保存すると普通にテキスト・エディタで読めることが多いです。

因みにfprintfなどを使って保存したファイルを秀丸エディタのバイナリ・モードで表示すると面白いですよ。ASCIIコード表と見比べてみてください。

投稿2016/02/03 12:43

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tada_tadaa

2016/02/03 14:55 編集

回答ありがとうございます。 リトルエンディアンという方式でデータを保存するのですね。初めて知りました。 >だから、E8, 03,00,00となります。(後ろに2つ00が続いていた筈です。) fwrite(&i, sizeof(int), 1, fp),fread(&i, sizeof(int), 1, fp)を試してみて、秀丸エディタのバイナリモー ドで開いてみると、 10 → 0A,00,00,00, 1000 → E8,03,00,00, となりました。fwrite(&i, 2, 1, fp)の方法でやると 10 → 0A,00, 1000 → E8,03, でした。コンピュータがどのように動作しているのかが少し分かるようで面白いです。 ちなみにfprintfを使って保存したファイルを秀丸エディタのバイナリ・モードで表示した結果 も面白かったです。 fprintf(fp, "%d %s", 12, "1hello"); 普通のモードで開くと 12 1hello ですが、バイナリ・モードだと 31,32,20,31,68,65,6C,6C,6F, でした。ASCIIコード表と見比べると 31→1、32→2、20→スペース、31→1、68→h、65→e、6c→l、6c→l、6f→o でした。アスキーコードの文字で保存されてても元はしっかりと、バイナリで 保存されてる?んですね。さらにそれがコンピュータの内部で2進数に変換されてCPUで 処理されてるとか考えると面白いです。
guest

0

どういう理屈でE8,03,になったのだろうか

10進1000は16進で3E8です。インテル系はリトルインディアン(バイトが反転する)のためにE803になります。

投稿2016/02/03 12:39

編集2016/02/03 12:41
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2016/02/03 13:00 編集

ついでに10進の10は改行(LF)コードです。 試す環境が今ないので、半角スペースがなぜ入るのか分からないですが・・・ あと、fwrite(&i, 2, 1, fp)は2バイトしか書き込まないので、fwrite(),fread()は以下のようなの記述をお勧めします。 fwrite(&i, sizeof(int), 1, fp),fread(&i, sizeof(int), 1, fp)
tada_tadaa

2016/02/03 13:15

回答ありがとうございます。 >半角スペースがなぜ入るのか分からないですが・・ エディタソフトのTeraPadで開こうとするときに、次のようなメッセージが表示されます。 「Null文字を含むファイルです。Null文字は半角スペースへ変換しました。」 と、あるのでどうやら半角スペースの正体はNull文字のようです。 エディタでは改行コードの下に半角スペースがあります。 インテル系はリトルエンディアン(リトルインディアン?)というのがあるんですね。初めて知りまし た。 回答ありがとうございました。
cateye

2016/02/03 13:46 編集

>半角スペースの正体はNull文字のようです。 あぁ、理解できましたw・・・Null==0なので0A00が書き込まれてたんですねd^^ リトルインディアン→リトルエンディアン ^^;;
nob.

2016/02/03 13:55

'リトルエンディアン':小さい方の端という意味です。 複数バイトからなる数値の場合、下の桁から格納される という事を表します。
tada_tadaa

2016/02/03 14:06 編集

>あと、fwrite(&i, 2, 1, fp)は2バイトしか書き込まないので、fwrite(),fread()は以下のようなの記述をお勧めします。 fwrite(&i, sizeof(int), 1, fp),fread(&i, sizeof(int), 1, fp) fwrite(&i, sizeof(int), 1, fp),fread(&i, sizeof(int), 1, fp)を試してみて、秀丸エディタのバイナリモー ドで開いてみると、 10 → 0A,00,00,00, 1000 → E8,03,00,00, となりました。fwrite(&i, 2, 1, fp)の方法でやると 10 → 0A,00, 1000 → E8,03, でした。独習Cの本には「sizeofを使うと、オブジェクトのサイズを自分で計算しなければならない というわずらわしさが避けられるばかりか、作成したコードをほかの環境に移植しても問題が起 こりません。」と書いてありました。 これって自分の環境(コンパイラ?)だとint型は4バイトっていうことだと思いますが、何かと便利 だと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問