C言語⑲(2025/09/08)

一般的な入出力

✅ 書籍の意図(Unix哲学)

  • Unix系OSでは「すべてはファイル」という抽象化があり、キーボード入力(stdin)や画面出力(stdout)も「ファイルディスクリプタ」として扱われます。
  • FILE* は C言語の標準ライブラリが提供する抽象型で、stdin, stdout, stderr はそれぞれ標準入力・出力・エラー出力を指すポインタです。

❌ しかし「装置をファイルとみなす」は構造的に誤解を招く

つまり、「ファイルとみなす」のはOSの抽象化レイヤーの話であって、C言語の構文や意味論とは別次元です。物理装置(キーボード、ディスプレイ)=ファイルではありません。

実際には、OSがそれらの装置に対して「ファイルのようなインターフェース」を提供しているだけです。

「C言語の標準入出力(stdin, stdout, stderr)は、OSが提供するストリームであり、標準ライブラリではそれらをファイルと同様のインターフェース(FILE*)で扱えるように抽象化している。これは、OSの設計思想に基づくものであり、物理的な装置がファイルであるという意味ではない。」
// fileDump 
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <Windows.h>
#include <string.h>


int main(int argc, char* argv[])
{
	if (argc <= 1) {
		printf("usage : fileDump fileName\n");
		return -1;
	}

	FILE* fp;
	unsigned char* rbuff = (unsigned char*)malloc(1024);
	if (rbuff == NULL) {
		printf("メモリ確保失敗!\n");
		return -1;
	}

	char* fname = argv[1];
	int err = fopen_s(&fp, fname, "rb");
	if (err != 0) {
		free(rbuff);
		return -1;
	}

	unsigned long addr = 0;
	printf("Dump File Name : %s\n", fname);
	while (true) {
		printf("%08x ", addr);
		int rnum = (int)fread(rbuff, sizeof(unsigned char), 16, fp);
		for (int ii = 0; ii < 16; ii++) {
			if (ii == 8)printf(" ");
			if (ii < rnum) {
				printf("%02x ", rbuff[ii]);
			}
			else {
				printf("   ");
			}
		}
		printf("   ");
		for (int ii = 0; ii < rnum; ii++) {
			printf("%c", (rbuff[ii] >= 0x20 && rbuff[ii] <= 0x7e) ? rbuff[ii] : '.');
		}

		addr += 16;
		printf("\n");
		if (feof(fp) != 0)break;
	}

	fclose(fp);

	free(rbuff);

	return 0;
}

実行結果

Dump File Name : UFO.png
00000000 89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52    .PNG........IHDR
00000010 00 00 00 40 00 00 00 1c  08 06 00 00 00 d1 25 b9    ...@..........%.
00000020 52 00 00 00 01 73 52 47  42 00 ae ce 1c e9 00 00    R....sRGB.......
00000030 00 04 67 41 4d 41 00 00  b1 8f 0b fc 61 05 00 00    ..gAMA......a...
00000040 00 09 70 48 59 73 00 00  16 25 00 00 16 25 01 49    ..pHYs...%...%.I
00000050 52 24 f0 00 00 00 44 65  58 49 66 4d 4d 00 2a 00    R$....DeXIfMM.*.
00000060 00 00 08 00 01 87 69 00  04 00 00 00 01 00 00 00    ......i.........
00000070 1a 00 00 00 00 00 03 a0  01 00 03 00 00 00 01 00    ................
00000080 01 00 00 a0 02 00 04 00  00 00 01 00 00 00 a0 a0    ................
00000090 03 00 04 00 00 00 01 00  00 00 46 00 00 00 00 00    ..........F.....
000000a0 78 2b f6 00 00 00 8b 49  44 41 54 58 47 ed 95 c1    x+.....IDATXG...
000000b0 0a 80 20 14 04 b5 ff ff  e7 f2 30 74 78 20 2f 51    .. .......0tx /Q
000000c0 a1 da 9d cb 74 a8 08 61  b6 5a 16 73 36 b8 dc 42    ....t..a.Z.s6..B
000000d0 6d 70 b9 84 03 cb e2 03  c0 b2 0c f7 b4 bb f1 59    mp.............Y
000000e0 46 37 c2 09 60 59 bc 01  b8 cb db 9b cf c8 36 c1    F7..`Y........6.
000000f0 09 60 59 bc 01 f8 26 6b  3e 36 f5 f5 fb 9d 00 96    .`Y...&k>6......
00000100 c5 1b 90 35 f3 77 9c 00  96 c5 1b 80 bb 8c 6e 44    ...5.w........nD
00000110 fc cf 46 b2 f7 cd 3e 1f  c9 de e7 04 b0 2c de 00    ..F...>......,..
00000120 fc 98 d8 60 d6 d8 6e 66  bf c7 09 60 59 c4 0f a0    ...`..nf...`Y...
00000130 94 0b 4f c1 38 2e 3e 89  a0 4e 00 00 00 00 49 45    ..O.8.>..N....IE
00000140 4e 44 ae 42 60 82                                   ND.B`.

このコードは、指定されたファイルの内容を16バイトずつ読み取り、アドレス・16進数・文字表示でダンプ(表示)するプログラムです。ファイル入出力の観点から、やさしく分解して解説しますね。

🗂️ ファイル入出力の流れ

① ファイル名の取得と確認

if (argc <= 1) {
    printf("usage : fileDump fileName\n");
    return -1;
}
  • 引数が足りない場合は使い方を表示して終了。

② メモリの確保

unsigned char* rbuff = (unsigned char*)malloc(1024);
  • 読み取り用のバッファ(rbuff)を1024バイト分確保。
  • 実際の読み取りは16バイトずつなので、1024は余裕を持たせたサイズです。

③ ファイルのオープン

int err = fopen_s(&fp, fname, "rb");
  • fopen_sでファイルを「読み込み専用(バイナリモード)」で開きます。
  • 開けなかった場合はメモリを解放して終了。

④ ファイルの読み取りと表示

int rnum = fread(rbuff, sizeof(unsigned char), 16, fp);
  • ファイルから最大16バイトを読み取ります。
  • 読み取ったバイト数(rnum)に応じて表示を調整。

表示内容:

  • アドレス(addr):ファイルのどこから読んでいるかを16進数で表示。
  • 16進数表示:読み取ったバイトを2桁の16進数で表示。
  • 文字表示:表示可能なASCII文字(0x20〜0x7E)ならそのまま、それ以外は.で表示。

⑤ 終了処理

fclose(fp);
free(rbuff);
  • ファイルを閉じて、確保したメモリを解放します。

🧠 まとめ:ファイル入出力のポイント

処理関連関数目的
ファイルを開くfopen_s読み取り準備
ファイルを読むfreadバイナリデータの取得
ファイルの終わり確認feof読み取り終了の判断
ファイルを閉じるfcloseリソースの解放

このプログラムは、バイナリファイルの中身を人間が見やすい形で表示する「ダンプツール」です。構造体の中身や実行ファイルの解析などにも応用できますよ。(by Copilot)

コメント

タイトルとURLをコピーしました