エディタを作る 2日目-1 ファイル読取
これだけ日数をかけて やって来たが、やっと「2日目」のチュートリアルである。 あまりにもペースが遅すぎる・・・というか 脱線し過ぎた。
「ファイルを読み込む」という エディタには必須の機能を試す。 そのオリジナルのソースが ↓ これ。
# include <stdio.h>
void file_print(char* filename) {
FILE *fp;
char str[10];
if((fp = fopen(filename, "r")) == NULL) {
printf("[error]can't open\n");
return;
}
while(fgets(str, sizeof(str), fp)) {
printf("%s", str);
}
fclose(fp);
}
int main(int argc, char *argv[]) {
printf("\e[2J\e[1;1H");//clear
if(argc != 2) {
printf("[error]illegal args\n");
} else {
file_print(argv[1]);
}
}
やっと それなりに長くなって来た。
1)fopen関数が使えない
これを そのまま Visual Stuido に通しても、警告が出てうまくビルド出来ない。 エラーメッセージは 以下 ↓ の通り。
fopen()関数の所で この関数は安全で無い(unsafe)なので、別の関数 fopen_s() を使うようにとの 英語のメッセージ。
「_CRT_SECURE_NO_WARNING を使えばエラーで無くなる、詳細はオンラインヘルプを読め!」と あまりに不親切な説明。
有る解説では、_CRT_SECURE_NO_WARNING を define定義してあげれば、エラーが出なくなり、fopen()がそのまま使えるようになるとの事だが…
解説通り ↓ こうやっても エラーが無くならず。(Visual Studio 2017で)
やっと発見した方法は、
1)[プロジェクト] → [FileReadのプロパティ] を実行、その後、
①[構成プロパティ] → ②[C/C++] → ③[プリプロセッサ]
→ ④[プリプロセッサの定義]の中に、
2) ;で先に区切って、_CRT_SECURE_NO_WARNING を追加で書き込む。
これでやっと fopen()がエラー無しで使えるようになった。
あまりにも面倒くさい! (Microsoftの意地の悪さ!!)
この方法でエラーのレベルを下げればでエラーが出なくなるかもしれないが、ソースを素直に書き換えることにした。
2)fopen_s()の使い方
fopen_s() 関数は C11の規格から追加された関数らしいので GCCでも使えるのかもしれないが、これだけ使えるように書くと、今度は他の開発環境でエラーになりかねない。 この関数が使えるC言語では、_STDC_LIB_EXT1_ マクロが定義されているらしいので これで切り替えるか?
→ あろうことか このマクロが Visual Studioでは定義されていない
(fopen_s関数が使えるのに・・・ 規定違反じゃね?)
しかたないので _MSC_VERマクロで Microsoft環境のC言語の時、切り替えることにした。
これなら ↓、どのC言語 開発環境でもそのままビルドが通るはず。
/* ソリューション名 プロジェクト
* main.cpp (2days → 1_FileRead → FileRead)
*
* ファイルの読み込み
*/
# include "color.h"
# include <stdio.h>
//# define _CRT_SECURE_NO_WARNINGS //fopen()を警告無しで使うには
//--- ファイルをオープンして、全行 画面に表示
void file_print(char* filename)
{
FILE *fp;
char str[10];
//# if defined(_STDC_LIB_EXT1_) //定義されていない=使えない
# if defined(_MSC_VER)
// fopen_s() = セキュリティ強化版 fopen
errno_t error = fopen_s(&fp, filename, "r");
# else
int error = 0;
fp = fopen(filename, "r");
if (fp == NULL) {
error = -1;
}
# endif
if(error != 0) {
printf("[error]can't open\n");
return;
}
while(fgets(str, sizeof(str), fp)) {
printf("%s", str);
}
fclose(fp);
}
int main(int argc, char *argv[])
{
clearScreen(); //← printf("\e[2J\e[1;1H");//clear
if(argc != 2) {
printf("[error]illegal args\n");
} else {
// main()の 引数でファイル名指定、その内容を表示
file_print( argv[1] );
}
int i = getchar();
return 0;
}
// End of main.c
このまま 開発環境から デバッグ実行すると、mainに引数が無いので、
[error]illegal args = 引数が異常だよ! と
ちゃんと 教えてくれる。
ここで、前の日記で書いたとおり、デバッグ時の コマンド引数 を セットをしてあげてから 動作確認。 (これも 中々 分かりずらいので 再度 掲載する)
3)コマンド引数のセット for デバッグ
① [デバッグ] → ② [~ のプロパティ] →
③ [構成プロパティ] → ④ [デバッグ] → ⑤ 「コマンド引数」
ここに 引数 として、「読み込みたいテキストファイルの ファイル名」を書き込んでおく。 すると その引数を付けて実行したのと同じ状態になる。 (例えば、ファイル名 TEST.txt 等)
もちろん 先に 読み込ませる テキストファイルを用意しておかなければいけない。 TeraPad等のテキスト エディタを使って、ファイル名:TEST-SJIS.txt を作ってみた。
文字の形式は S-JIS ・・・ つまり、SHIFT-JIS形式にしておく。
このファイル名に合わせて、コマンド引数の所も、 TEST-SJIS.txt に変更。 問題は、このファイルを何処のフォルダに置いておくべきか?だ。
デバッグ用に コマンド引数をセットしたので、今度は
変数 argc が 2になっているので 意図した通り file_print() が実行される。
ファイルが存在しない場合、fopen_s()関数は 0以外(正確には2) を返すようだ。↓
そして、通常はフォルダ名等をいっしょに指定しなければ、「実行ファイルと同じフォルダ」から読み込まれる と思いがちだが、Visual Studioの開発環境では 少し違うので注意が必要だ。
Visual Studioでは ビルドする際に ① デバッグ ②リリースの 2つの形式がある。 開発途中は ①デバッグの状態だ。 すると、実行ファイルも(ソースファイルがあるフォルダより 1つ上の)¥Debugフォルダ内に作られる。
そもそも Debugフォルダが2つ存在するので さらに混乱する。
プロジェクト フォルダの下にある Debugフォルダは そもそも人が使う事は無い(PCが使うだけ) 実行ファイルが作られるのは1つ上の ソリューション・フォルダ下の Debugフォルダ内である。
開発環境に限った事なのだが、フォルダ指定なしでそのまま読み取れる位置は、「ソースファイルが入っているのと同じフォルダ位置だ」と覚えておくと間違えない。
これは、本当に 良く勘違いしがちなので 要注意!
つまり、デバッグ・モードであろうと、リリース・モードであろうと同じフォルダ位置から ファイルが読み取れるのだ。(DebugやReleaseフォルダがデフォルトフォルダにはならない・・・ ここにexeファイルが存在しても)
そして、exe 実行ファイル単体で 直接 実行した時(開発環境を使わなかった時)は、exeファイルが入っているのと同じフォルダが デフォルトフォルダになる・・・のも注意が必要。
3)文字セットの問題
正しい位置に テキストファイルを置いて、デバッグ実行すれば、ちゃんと TEST-SJIS.txt ファイルが読み取られ、その中の文字列が画面に表示される。
たとえ、全角文字(漢字)であっても。
ただし、これは 文字コードが Shift-JIS だからであり、最近の標準的な UNICODEでは こうはいかない。
試しに、UTF-8 や UTF-8N の文字形式で同じ文字列のファイルを作り、FileRead.exe で 読み込ませ、表示させてみると、どちらであっても!
UTF-8Nの場合の 文字化け ↑
「BOM」という このファイルが UTF-8の文字コードである事を示す 3バイト識別コードが埋め込まれたファイルは、普通の UTF-8 と分類される。(UTF-8Nの’N'は None BOM ・・・ BOMが付いていないシンプルな UTF-8ファイルという意味) これも UNICODEの一種。
だから、UTF-8であれば ソフトでファイルの形式を識別できるはず。 ところが・・・ UTF-8であっても自動判別はしてくれないようで、同じ様に文字化けする。 ガッカリ!
UTF-8 の場合の文字化け ↑ 文字コードの情報(BOM)が (1234の前)ファイルの先頭に存在するので それもおかしな表示に化ける。
ちなみに、「BOM」とは Byte Order Mark の略で、このファイルは Unicode 形式であると判別させるための情報であり、ファイルの先頭に「0xEF, 0xBB, 0xBF」という3バイトが付く。 (半角カタカナの ソ =’ソ’ が 見てとれるが、これが3バイト目の 0xBF である)
ASCII(英数字のみ)や シフト-JIS(ANSI) のファイルだけを 相手にしていれば、問題無いが 今の時代 テキスト・エディタで ユニコードが編集 出来なくては 話にならないだろう。
さて、どうしたものか?
。