ページ 1 / 1
ダンププログラムについて教えてください
Posted: 2012年5月17日(木) 22:20
by ( ゚д゚ )
Ascllのところに日本語も表示できるようにしたいのですがどうすればいいのですか?
~~~~~~~~~~~~~~
if(data < 0x20 || data >= 0x7F){
buff = '.';
else{
buff = data;
printf( "%02X ", data );
}
~~~~~~~~~~~~~~
Re: ダンププログラムについて教えてください
Posted: 2012年5月17日(木) 22:56
by softya(ソフト屋)
文字コードがわからないと処理出来ないので、OSの種類や詳細な開発環境の限定をお願いします。
Re: ダンププログラムについて教えてください
Posted: 2012年5月17日(木) 23:00
by ( ゚д゚ )
OS:Windows7
開発環境:VC 2008 コマンドプロントで作成
です。
Re: ダンププログラムについて教えてください
Posted: 2012年5月17日(木) 23:55
by softya(ソフト屋)
特に何もせず日本語環境でfread()したと想定すれば文字コードはshift-jisであろうと思われます。
なので、Shift-jisの全角コードであるか判定すれば2バイト文字なのか1バイト文字なのかは区別できます。
「C言語プログラミングの質問です。 文字コードの全角・半角判定で悩んでいます。 - Yahoo!知恵袋」
http://detail.chiebukuro.yahoo.co.jp/qa ... 1116019231
「半角と全角の混在するShiftJIS文字コードの扱い方(C/C++) - プログラミング講座 - fuku研究所」
http://www5f.biglobe.ne.jp/~fuku-labo/l ... /2/076.htm
Re: ダンププログラムについて教えてください
Posted: 2012年5月18日(金) 21:33
by ( ゚д゚ )
ありがとうございます。
日本語で表示することができました。
あともう一つ聞きたいのですが、16個目のデータが2バイト(漢字、全角文字など)だった場合、改行前に1バイト、改行後に1バイト表示してしまいます。
改行前に2バイトを表示したいのですがうまいくいきません。
現在のプログラムはこんな感じです
コード:
#include <stdio.h>
#include <conio.h>
void main()
{
FILE *fp;
int data;
int _data;
int i;
int end = 0;
unsigned long addr;
char buf[100];
while(1)
{
getch();
// 実際にはgetchでファイル名を入力させ文字に変換し、
// ファイル名とします
// 今は、関係ないから直接読み込んでます
// ファイルを開く
fp = fopen("main.cpp", "rb");
if(fp == NULL)
{
printf("ファイルがオープンできません.\n");
return;
}
// データの終わりまでロード
for(addr = 0; end!=1; addr += 16)
{
printf("%08lX ", addr);
// 16進データ
for(i = 0; i < 16; i++)
{
// 1バイト読み込み
if((data = getc(fp) ) == EOF)
{
buf[i] = '\0';
for(;i < 16; i++)
{
printf(" ");
}
printf(" %s\n", buf);
fclose(fp);
end=1;
return;
}
if( data < 0x80 )
{
// 制御文字なら
if( data < 0x20 )
{
buf[i]='.'; // .を代入
}
else // 英数字なら
{
buf[i] = data; // そのまま
}
}
// 0x80以上
else
{
// 半角カナ
if( (data>0x9F)&&(data<0xE0) )
{
buf[i] = data; // そのまま
}
// 2バイト文字の1バイト目なら・・
else
{
buf[i] = data; // 1バイト目を代入
}
}
printf("%02X ", data);
}
buf[i] = '\0';
printf(" %s\n", buf);
}
}
}
Re: ダンププログラムについて教えてください
Posted: 2012年5月18日(金) 21:50
by softya(ソフト屋)
1バイトづつ読んでいるので面倒だと思います。
mallocしたメモリにファイル内容一括読み込み後に処理してはどうでしょうか?
※ その場合次の行の先頭は何らかの表示できない文字扱いが必要ですが。
[補足] あるいは、最後が2バイト文字の先頭ならその行だけ17バイト表示して次の行は15バイト表示するとか変則的な処理が必要です。
Re: ダンププログラムについて教えてください
Posted: 2012年5月18日(金) 23:13
by ( ゚д゚ )
mallocだとメモリ以上のファイルを読み込めないのであまりつかいたくありません。
16個目のデータが、2バイト文字(日本語)が1バイト目か2バイト目かわかればいけそうなのですが、なにかよい調べかはありませんか?
コード:
// 半角カナ
if( (data>0x9F)&&(data<0xE0) )
{
buf[i] = data; // そのまま
}
// 2バイト文字の1バイト目なら・・
※これでは1バイト目でも2バイト目でも条件が成立してしまう
else
Re: ダンププログラムについて教えてください
Posted: 2012年5月18日(金) 23:23
by softya(ソフト屋)
今時メモリで困るとも思えませんが制御は面倒になります。
(1)16バイト目で2バイト文字の先頭なら次の1バイトをfgetcする。
(2)もし、それがEOFならこの行を表示して終了する。2バイト文字の先頭しか無かったので該当文字なし"."とする。
(3)読み込めた場合は、bufに追加。
(4)ここで次の行の1バイト目を読み込んでいる事になるので、次の行の先頭としての読み込みは行わないで処理する。
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 09:29
by ( ゚д゚ )
ありがとうございます。
うまくいったと思ったのですが・・
読み込むデータが
a.txt
あaいiうuえeおoかきくけこさしすせそ
だった場合「か」は改行前と改行後でデータが分かれてますが改行前で表示できています。
改行後に2バイト文字の2バイト目が表示されないようにもできました。
ですが、読み込むデータが
a.txt
阿鋳鵜得御下記九毛個沙師巣背祖(表示する行が16バイトできっちりおさまる場合)
だった場合
「阿鋳鵜得御下記九」までは普通に表示されるのですが「九」の横に「・」が表示され
2行目からは「_ム個沙師巣背祖」と表示されます。
※_はスペースです。
「16バイト目で2バイト文字の先頭なら」条件式がわかりません。
なにか特別な関数があるのでしょうか?
コード:
#include <stdio.h>
#include <conio.h>
#include <mbctype.h>
void main()
{
FILE *fp;
int data;
int _data;
int flag = 0;
int flag2 = 0;
int i;
int end = 0;
int ss = 0;
unsigned long addr;
char buf[100] = "";;
while(1)
{
// 初期化
for( ss = 0; ss < 100; ss++ ){
buf[ss] = '\0';
}
getch();
// ファイルを開く
fp = fopen("a.txt", "rb");
if(fp == NULL)
{
printf("ファイルがオープンできません.\n");
return;
}
// データの終わりまでロード
for(addr = 0; end!=1; addr += 16)
{
printf("%08lX ", addr);
// 16進データ
for(i = 0; i < 16; i++)
{
if( flag )
{
fseek(fp, -1, SEEK_CUR );
flag = 0;
flag2 = 1;
}
// 1バイト読み込み
if((data = getc(fp) ) == EOF)
{
buf[i] = '\0';
for(;i < 16; i++)
{
printf(" ");
}
printf(" %s\n", buf);
fclose(fp);
end=1;
return;
}
// 2行目で2バイト文字の2バイト目を表示するとおかしくなるので
// スペースを入れる
if( flag2 )
{
buf[i] = ' ';
flag2 = 0;
}
else if( data < 0x80 )
{
// 制御文字なら
if( data < 0x20 )
{
buf[i]='.'; // .を代入
}
else // 英数字なら
{
buf[i] = data; // そのまま
}
}
// 0x80以上
else
{
// 半角カナ
if( (data>0x9F)&&(data<0xE0) )
{
buf[i] = data; // そのまま
}
// 2バイト文字の1バイト目なら・・
else
{
buf[i] = data; // 1バイト目を代入
//_ismbslead( data, fp );
if( i == 15 )
{
if((_data = getc(fp)) == EOF)// 次のデータをロード(fpは1個動く)
{
buf[i] = '.';
}else{
buf[i+1] = _data; //
flag = 1;
}
}
}
}
printf("%02X ", data);
}
printf(" %s\n", buf);
}
}
}
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 12:58
by softya(ソフト屋)
特殊な関数はありません。
全てiなどから判断するしかありませんが、この処理のままだとすごく条件がややこしくなることは間違いないでしょう(既にコードがややこしいです)。
あまり直したくないコードになるのでシンプルに書いたものを参考に提示しますのでお待ち下さい。
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 14:35
by かずま
入力ファイルのサイズが 16の倍数のとき、アドレスを余計に表示するバグがありますが、
コード:
#include <stdio.h>
#include <ctype.h>
int is_sjis1(unsigned char c) { return (c ^ 0x20) - 0xA1u < 60; }
int is_sjis2(unsigned char c) { return c >= 0x40 && c <= 0xfc && c != 0x7f; }
int get_c2(int c1, FILE *fp)
{
int c2;
if (!is_sjis1(c1) || (c2 = fgetc(fp)) == EOF) return 0;
ungetc(c2, fp);
return is_sjis2(c2) ? c2 : 0;
}
void dump(FILE *fp)
{
char buf[20]; int i, c1, c2 = 0; long addr;
for (addr = 0; ; addr += 16) {
printf("%08X ", addr);
for (i = 0; i < 16; i++) {
if ((c1 = fgetc(fp)) == EOF) {
printf("%*s %.*s\n", (16 - i) * 3, "", i, buf);
return;
}
printf("%02X ", c1);
if (c2)
buf[i] = c2, c2 = 0;
else
buf[i] = ((c2 = get_c2(c1, fp)) || isprint(c1)) ? c1 : '.';
if (c2 && i == 15)
buf[16] = c2, c2 = ' ';
}
printf(" %.*s\n", c2 ? 17 : 16, buf);
}
}
int main(void)
{
FILE *fp = fopen("a.txt", "rb");
if (fp == NULL) {
printf("ファイルがオープンできません.\n");
return 1;
}
dump(fp);
fclose(fp);
return 0;
}
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 14:46
by かずま
かずま さんが書きました:入力ファイルのサイズが 16の倍数のとき、アドレスを余計に表示するバグがありますが、
半角片仮名が出ないバグがありました。
int is_print(unsigned char c) { return isprint(c) || c >= 0xa1 && c <= 0xdf; }
を追加し、
buf
= ((c2 = get_c2(c1, fp)) || isprint(c1)) ? c1 : '.';
の isprint を is_print に変更してください。
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 15:36
by softya(ソフト屋)
本当は全部書きなおすのは良くないと思うのですが色々あって原型が残っていません。
あと、このぐらい色々やらないとお望みの結果は得られないと言うことです。
※ かずまさんのより長いです。
コード:
#include <stdio.h>
#include <conio.h>
#include <mbctype.h>
// 16進数の表示。
void PrintHex(int addr,int offset,int data)
{
// EOFなら
if( data == EOF ) {
// 先頭でなければ空白で埋める
if( offset > 0 ) {
for(;offset < 16; offset++) {
printf(" ");
}
}
} else {
// 先頭ならアドレスを表示
if( offset==0 ) {
printf("%08lX ", addr);
}
// 16進の表示
printf("%02X ", data);
}
}
// 文字を得る(全角・半角)
int GetChar(int datas[],char *curText,FILE *fp)
{
int codesize;
int data;
int i;
// 最大2バイト
for( i=0 ; i<2 ; i++ ) {
// 文字コードのサイズ。
codesize = i+1;
// 1バイト読み込み。もしEOFなら
if( (data = datas[i] = getc(fp) ) == EOF ) {
// これが2バイト目
if( i == 1 ) {
curText[i-1] = '.'; // 1つ前の文字は全角不成立で表示不可
}
curText[i] = '\0';//文字列終端
// EOFなのでここまで。
break;
} else {
// 2バイト目なら
if( i == 1 ) {
// 2バイト目のコード
curText[i] = data;//文字。2バイト目
} else {
// 全角文字判定
if( ((0x81<=data)&&(data<=0x9F)) || ((0xE0<=data)&&(data<=0xFC)) ){
// 全角の1バイト目のコード
curText[i] = data;//文字。
} else {
// 半角文字コードで表示可能
if( ((0x20<=data)&&(data<=0x7E)) || ((0xA1<=data)&&(data<=0xDF)) ){
curText[i] = data; // そのまま
} else {
curText[i] = '.'; // 表示不可
}
curText[i+1] = '\0';//文字列終端
// 1バイト文字なのでここで終了。
break;
}
}
curText[i+1] = '\0';//文字列終端
}
}
// 有効データ数を返す。
return codesize;
}
// テキストの表示。
void PrintText(char textbuf[])
{
printf(" %s\n", textbuf);
}
int main()
{
FILE *fp;
int data,i,codesize,offset,fn;
unsigned long addr;
char textbuf[100] = "";
int datas[2];
char *curText = textbuf;
char *fileNames[] = {
"a.txt",
"b.txt",
"c.txt",
"d.txt",
NULL,
};
for( fn=0 ; fileNames[fn]!=NULL ; fn++ ) {
// getch();
// ファイルを開く
fp = fopen(fileNames[fn], "rb");
if(fp == NULL)
{
printf("ファイルがオープンできません.\n");
return -1;
}
printf ("-- file=%s --\n",fileNames[fn]);
// データの終わりまで処理
data = 0;
addr = 0;
offset = 0;
while( data!=EOF ) {
// 文字を得る。
codesize = GetChar(datas,textbuf+offset,fp);
// 得られた文字サイズだけ処理
for( i=0; i<codesize ; i++ ) {
// 16進の表示
PrintHex(addr,offset,datas[i]);
// 最後の文字(EOFの情報)。
if( EOF == (data=datas[i]) ) {
break;//EOFなら抜ける
}
// アドレスとオフセットの計算
offset++;
addr++;
// 改行位置まで来ていたらテキストを表示
if( offset >= 16 ) {
offset -= 16;
// テキストの表示。
PrintText(textbuf);
// 行をまたがる2バイトコードなら
if( (i==0)&&(codesize==2) ) {
// 先頭の文字コードは表示不可とする。
textbuf[0] = '.';
textbuf[1] = '\0';
} else {
// テキストバッファを先頭に
textbuf[0] = '\0';
}
}
}
}
// 残りの文字があるなら。
if( offset > 0 ) {
// テキストの表示。
PrintText(textbuf);
}
// ファイルを閉じる。
fclose(fp);
}
getch();
}
実行結果
コード:
-- file=a.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C 20 8B 阿鋳鵜得御下記 九
00000010 E3 20 8C C2 8D B9 8E 74 91 83 94 77 91 63 8D AA . 個沙師巣背祖根
00000020 96 D1 8C C2 8D B9 8E 74 91 83 94 77 91 63 8D AA 毛個沙師巣背祖根
00000030 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C 8B E3 阿鋳鵜得御下記九
-- file=b.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C B9 8B 阿鋳鵜得御下記ケ九
00000010 E3 .
-- file=c.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 阿鋳鵜得御
-- file=d.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C 阿鋳鵜得.
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 17:30
by ( ゚д゚ )
かずまさん、softya(ソフト屋)さんどうもありがとうございました。
参考にさせていただきます。
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 19:05
by かずま
かずま さんが書きました:入力ファイルのサイズが 16の倍数のとき、アドレスを余計に表示するバグがありますが、
上記のバグの修正版です。
コード:
#include <stdio.h>
#include <ctype.h>
int is_sjis1(unsigned char c) { return (c ^ 0x20) - 0xA1u < 60; }
int is_sjis2(unsigned char c) { return c >= 0x40 && c <= 0xfc && c != 0x7f; }
int is_print(unsigned char c) { return isprint(c) || c >= 0xa1 && c <= 0xdf; }
int get_c2(int c1, FILE *fp)
{
int c2;
if (!is_sjis1(c1) || (c2 = fgetc(fp)) == EOF) return 0;
ungetc(c2, fp);
return is_sjis2(c2) ? c2 : 0;
}
void dump(FILE *fp)
{
char buf[20]; int i, c1, c2 = 0; long addr;
for (addr = 0; ; addr += 16) {
for (i = 0; i < 16; i++) {
if ((c1 = fgetc(fp)) == EOF) {
if (i) printf("%*s %.*s\n", (16 - i) * 3, "", i, buf);
return;
}
if (i == 0) printf("%08lX ", addr);
printf("%02X ", c1);
if (c2)
buf[i] = c2, c2 = 0;
else
buf[i] = (c2 = get_c2(c1, fp)) || is_print(c1) ? c1 : '.';
if (c2 && i == 15)
buf[16] = c2, c2 = '_';
}
printf(" %.*s\n", c2 ? 17 : 16, buf);
}
}
int main(int argc, char *argv[])
{
if (argc <= 1) dump(stdin);
else {
int i;
for (i = 1; i < argc; i++) {
FILE *fp = fopen(argv[i], "rb");
if (!fp) return printf("can't open %s\n", argv[i]), 1;
dump(fp);
fclose(fp);
}
}
return 0;
}
実行結果
コード:
00000000 88 A2 92 92 89 00 93 BE 8C E4 89 BA 8B 4C 8B E3 阿鋳..得御下記九
00000010 96 D1 8C C2 8D B9 8E 74 91 83 94 77 91 63 0D 0A 毛個沙師巣背祖..
ダンプするのはバイナリファイルですから、0 も含まれることがあるんですよね。
同じファイルの softya(ソフト屋)さんのプログラムの実行結果
コード:
-- file=a.txt --
00000000 88 A2 92 92 89 00 93 BE 8C E4 89 BA 8B 4C 8B E3 阿鋳
00000010 96 D1 8C C2 8D B9 8E 74 91 83 94 77 91 63 0D 0A 毛個沙師巣背祖..
ファイルがオープンできません.
Re: ダンププログラムについて教えてください
Posted: 2012年5月19日(土) 19:29
by softya(ソフト屋)
2バイト目の漢字コードチェックサボっちゃったのがマズかったですね。
まだバグがある可能性がある事をお断りしておきます。
コード:
#include <stdio.h>
#include <ctype.h>
// 16進数の表示。
void PrintHex(int addr,int offset,int data)
{
// EOFなら
if( data == EOF ) {
// 先頭でなければ空白で埋める
if( offset > 0 ) {
for(;offset < 16; offset++) {
printf(" ");
}
}
} else {
// 先頭ならアドレスを表示
if( offset==0 ) {
printf("%08lX ", addr);
}
// 16進の表示
printf("%02X ", data);
}
}
// 半角チェック
int is_hankaku(int data)
{
return ((0x20<=data)&&(data<=0x7E)) || ((0xA1<=data)&&(data<=0xDF));
}
// 文字を得る(全角・半角)
int GetChar(int datas[],char *curText,FILE *fp)
{
int codesize;
int data;
int i;
// 最大2バイト
for( i=0 ; i<2 ; i++ ) {
// 文字コードのサイズ。
codesize = i+1;
// 1バイト読み込み。もしEOFなら
if( (data = datas[i] = getc(fp) ) == EOF ) {
// これが2バイト目
if( i == 1 ) {
curText[i-1] = '.'; // 1つ前の文字は全角不成立で表示不可
}
curText[i] = '\0';//文字列終端
// EOFなのでここまで。
break;
} else {
// 2バイト目なら
if( i == 1 ) {
// 2バイト目のコードが正しい?
if( ((0x40<=data)&&(data<=0x7E)) || ((0x80<=data)&&(data<=0xFC)) ){
curText[i] = data;//文字。2バイト目
} else {
curText[i-1] = '.'; // 1つ前の文字は全角不成立で表示不可
// 半角文字コードで表示可能
if( is_hankaku(data) ){
curText[i] = data; // そのまま
} else {
curText[i] = '.'; // 表示不可
}
}
} else {
// 全角文字判定
if( ((0x81<=data)&&(data<=0x9F)) || ((0xE0<=data)&&(data<=0xFC)) ){
// 全角の1バイト目のコード
curText[i] = data;//文字。
} else {
// 半角文字コードで表示可能
if( is_hankaku(data) ){
curText[i] = data; // そのまま
} else {
curText[i] = '.'; // 表示不可
}
curText[i+1] = '\0';//文字列終端
// 1バイト文字なのでここで終了。
break;
}
}
curText[i+1] = '\0';//文字列終端
}
}
// 有効データ数を返す。
return codesize;
}
// テキストの表示。
void PrintText(char textbuf[])
{
printf(" %s\n", textbuf);
}
int main()
{
FILE *fp;
int data,i,codesize,offset,fn;
unsigned long addr;
char textbuf[100] = "";
int datas[2];
char *curText = textbuf;
char *fileNames[] = {
"a.txt",
"b.txt",
"c.txt",
"d.txt",
"e.txt",
NULL,
};
for( fn=0 ; fileNames[fn]!=NULL ; fn++ ) {
// getch();
// ファイルを開く
fp = fopen(fileNames[fn], "rb");
if(fp == NULL)
{
printf("ファイルがオープンできません.\n");
return -1;
}
printf ("-- file=%s --\n",fileNames[fn]);
// データの終わりまで処理
data = 0;
addr = 0;
offset = 0;
while( data!=EOF ) {
// 文字を得る。
codesize = GetChar(datas,textbuf+offset,fp);
// 得られた文字サイズだけ処理
for( i=0; i<codesize ; i++ ) {
// 16進の表示
PrintHex(addr,offset,datas[i]);
// 最後の文字(EOFの情報)。
if( EOF == (data=datas[i]) ) {
break;//EOFなら抜ける
}
// アドレスとオフセットの計算
offset++;
addr++;
// 改行位置まで来ていたらテキストを表示
if( offset >= 16 ) {
offset -= 16;
// テキストの表示。
PrintText(textbuf);
// 行をまたがる2バイトコードなら
if( (i==0)&&(codesize==2) ) {
// 先頭の文字コードは表示不可とする。
textbuf[0] = '.';
textbuf[1] = '\0';
} else {
// テキストバッファを先頭に
textbuf[0] = '\0';
}
}
}
}
// 残りの文字があるなら。
if( offset > 0 ) {
// テキストの表示。
PrintText(textbuf);
}
// ファイルを閉じる。
fclose(fp);
}
getch();
}
コード:
-- file=a.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C 00 8B 阿鋳鵜得御下記.九
00000010 E3 20 8C C2 8D B9 8E 74 91 83 94 77 91 63 8D AA . 個沙師巣背祖根
00000020 96 D1 8C C2 8D B9 8E 74 91 83 94 77 91 63 8D AA 毛個沙師巣背祖根
00000030 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C 8B E3 阿鋳鵜得御下記九
-- file=b.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 89 BA 8B 4C B9 8B 阿鋳鵜得御下記ケ九
00000010 E3 .
-- file=c.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C E4 阿鋳鵜得御
-- file=d.txt --
00000000 88 A2 92 92 89 4C 93 BE 8C 阿鋳鵜得.
-- file=e.txt --
00000000 88 A2 92 92 89 00 93 BE 8C E4 89 BA 8B 4C 8B E3 阿鋳..得御下記九
00000010 96 D1 8C C2 8D B9 8E 74 91 83 94 77 91 63 0D 0A 毛個沙師巣背祖..