2023 年度「数学特論」 2024-02-07

§15.1 ファイルを dump するプログラム

#include <stdio.h>

int main() {
  printf("hello, world\n");
}

上の内容をもつファイルを引数として指定すると次のように出力するプログラムである。

0000-0000  23 69 6e 63 6c 75 64 65|20 3c 73 74 64 69 6f 2e  #include <stdio.
0000-0010  68 3e 0d 0a 0d 0a 69 6e|74 20 6d 61 69 6e 28 29  h>    int main()
0000-0020  20 7b 0d 0a 20 20 70 72|69 6e 74 66 28 22 68 65   {    printf("he
0000-0030  6c 6c 6f 2c 20 77 6f 72|6c 64 5c 6e 22 29 3b 0d  llo, world\n");
0000-0040  0a 7d 0d 0a                                       }

ディスク上に記録されたデータをそのまま出力する。

左の八桁は先頭から何バイト目かを十六進法で示している。 中央の部分は、データを十六進法で示している。 まん中の「|」は、単なる中央の目印である。 右は、文字に対応するバイトはその文字で示したものである。 文字に対応しないバイトのところは空白にしてある。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char *argv[]) {
  FILE* in;
  int c, n;
  char str[16+1];   /* 右に表示する文字列 */

  if (argc != 2) {
    fprintf(stderr, "使い方はソ\ースファイルを見てください.\n");
    exit(1);
  }
  if ((in = fopen(argv[1], "rb")) == NULL) {
    fprintf(stderr, "\"%s\"を開けません.\n", argv[1]);
    exit(1);
  }
  for (n = 0; (c = getc(in)) != EOF; n++) {
    if (n % 16 == 0) {                          /* 左の、何バイト目かの表示 */
      printf("%04x-%03x0  ", n / 65536, n % 65536 / 16);
    }
    printf("%02x", c);              /* 中央の欄の表示 */
    str[n % 16] = isprint(c) ? c : ' ';
    if (n % 16 == 15) {
      printf("  %s\n", str);        /* 右の欄の表示 */
    } else if (n % 16 == 7) {
      printf("|");
    } else {
      putchar(' ');
    }
  }
  for (   ; n % 16 != 15; n++) {    /* 残りの処理 */
    printf("   ");
    str[n % 16] = ' ';
  }
  str[15] = ' ';
  printf("    ");
  puts(str);    
}

改行は、Windows では十六進法で 0d, 0a で表される。 前に書いたファイルを読み出すプログラムでは、 改行は \n というひとつの文字だったが、 このプログラムは 0d, 0a と出力する。

プログラムが始まってすぐの、 fprintf(stderr, "使い方はソ\ースファイルを見てください.\n"); について。 関数 fprintf()printf() と似ているが、ファイルに書き出すものである。 ここでは stderr に書き出している。 stderr は画面であるが、 ファイルに出力リダイレクトした場合でも画面に書かれる、という点で異なる。

その少し下の fopen() では、モードは "rb" である。 この b はバイナリーの意味で、 上に述べたように改行の 0d, 0a を \n 一文字に変換しない。

中央の欄の表示 の次の行。 「条件 ? 式1 : 式2」は三項演算子で、 これ全体は、条件 が真ならば 式1, 偽ならば 式2 になる、という約束である。 関数 isprint() は、印字可能なバイトなら真、そうでなければ偽、を返す。 式1 として単に isprint(c) と書くと、真ならば真、偽ならば偽、と解釈される。

残りの処理 の部分は、もう少しうまく書けるかもしれない。

§15.2 応用

#include <stdio.h>

int main() {
  printf("こんにちは、世界\n");
}

上のファイルを上のプログラムで dump すると

0000-0000  23 69 6e 63 6c 75 64 65|20 3c 73 74 64 69 6f 2e  #include <stdio.
0000-0010  68 3e 0d 0a 0d 0a 69 6e|74 20 6d 61 69 6e 28 29  h>    int main()
0000-0020  20 7b 0d 0a 20 20 70 72|69 6e 74 66 28 22 82 b1   {    printf("
0000-0030  82 f1 82 c9 82 bf 82 cd|81 41 90 a2 8a 45 5c 6e           A   E\n
0000-0040  22 29 3b 0d 0a 7d 0d 0a|                         ");  }

となる。いわゆる日本語は、いわゆる日本語としては表示されない。 プログラムを改良し、

0000-0000  23 69 6e 63 6c 75 64 65|20 3c 73 74 64 69 6f 2e  #include <stdio.
0000-0010  68 3e 0d 0a 0d 0a 69 6e|74 20 6d 61 69 6e 28 29  h>    int main()
0000-0020  20 7b 0d 0a 20 20 70 72|69 6e 74 66 28 22 82 b1   {    printf("こ
0000-0030  82 f1 82 c9 82 bf 82 cd|81 41 90 a2 8a 45 5c 6e  んにちは、世界\n
0000-0040  22 29 3b 0d 0a 7d 0d 0a|                         ");  }

のように表示されるものは書けるだろうか。

おまけ

「計算数学a」の (5.3.3) にあった 「伊藤*、田中**、藤村**」が気になる人は、 ネットで検索してみよう。


岩瀬順一