http://oshiete1.goo.ne.jp/qa5626799.html
問題
第1引数に指定したファイルからバイナリーモードで1バイトずつファイルを読み込み、ファイルの内容を16進数で示した物を第2引数に指定したファイルに書き込む、プログラムを作成せよ。ただし、16バイトごとに改行を入れること。
ファイルイメージ file1.txt
aaaaa
bbbbb
ccccc
ddddd
eeeee
実行例
$ ./a.out file1.txt file2.txt
$ cat file2.txt
61 61 61 61 61 0D 0A 62 62 62 62 62 0D 0A 63 63
63 63 63 0D 0A 64 64 64 64 64 0D 0A 65 65 65 65
65 0D 0A
解答例
#include <stdio.h>
int main(int argc, char *argv[]){
FILE *fr, *fw;
int ret_code = 0;
int byte_code, line_counter;
if(argc < 3){
puts("引数を2つ指定してください。");
ret_code = -1;
}else if((fr = fopen(argv[1], "rb")) == NULL){
puts("ファイルを読み取れませんでした。");
ret_code = -2;
}else{
if((fw = fopen(argv[2], "w")) == NULL){
puts("ファイルを書き込めません。");
ret_code = -3;
}else{
line_counter = 0;
while((byte_code = fgetc(fr)) != EOF){
fprintf(fw, "%02X", byte_code);
line_counter++;
if((line_counter & 0xf) == 0){
putc('\n', fw);
}else{
putc(' ', fw);
}
}
putc('\n', fw);
fclose(fw);
}
fclose(fr);
}
return ret_code;
}
解説のようなもの
この問題はファイル入出力の基礎を問う。
fopen でファイルを開く際、バイナリ モードで開くことを明示する "rb" を使用したが、Linux 環境では特に意味はない。Windows では改行の解釈に関して挙動に違いが出る。
次に、16進数変換に関して、計算するサブルーチンを作るか、fprintf を使うか、sprintf を元に書き込むかの選択肢がある。一番簡単な fprintf を使用した。"%02X" で、2ケタの16進数に変換して書き込む。値が 0x10 に満たない場合は 0 でパディングされる。
また、16バイト毎に改行を挟む手法に関して、カウンターの使い方は大きく3種類考えられる。
1つはline_counter をインクリメントし、16に達したら改行を入れ、0 に戻すパターン。簡潔で分かりやすく、16を別の値に変えやすいためメンテナンス性が良い。
line_counter++;
if(line_counter >= 16){
putc('\n', fw);
line_counter = 0;
}else{
putc(' ', fw);
}
2つ目は解答例のように bit 演算で求めるパターン。line_counter をリセットする必要がないため、わずかに高速。
line_counter++;
if((line_counter & 0xf) == 0){
putc('\n', fw);
}else{
putc(' ', fw);
}
3つ目は剰余で求めるパターン。メンテナンス性は良いが、速度に関しては要検証。
line_counter++;
if((line_counter % 16) == 0){
putc('\n', fw);
}else{
putc(' ', fw);
}
なお、実行例の場合、改行コードとして OD OA が使用されている。これは Windows 系の改行コードを表している。
Linux の場合はここが OA となる。