「C言語/ファイル入出力」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
scanf系の戻値チェック漏れ多数。文字列に読み込んで字句解析する安全なコードを示すべきでは?そうするにしても、Cではバッファ長の管理が煩雑になりがちでバッファオーバーランの温床。
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎ワイド文字のファイル入出力: キャラクターセットとエンコーディングの混同
タグ: 2017年版ソースエディター
876 行
とはいえ、最近のWindows用テキストエディタでは(Linuxでは標準的に採用されている)UTF-8も表示できるのが一般的なので、特に文字化けなどの起きないかぎり、むりに文字コードを変える必要は無い。
 
 
== ワイド文字のファイル入出力 ==
=== Linuxの場合 ===
Windowsでいう「Unicode」が、マイクロソフト社の自称にすぎず、実態は国際規格とは違う。
 
なので、説明の簡単のために、まず
Linuxで説明する。
 
 
 
;読み取りたいテキスト
<pre>
これはテストです。
 
aaaaaaaaaaa
</pre>
 
 
;Linuxの場合のコード例
<syntaxhighlight lang="C">#include <stdio.h>
#include <locale.h>
#include <wchar.h>
 
int main(void)
{
setlocale(LC_ALL, "ja_JP.UTF-8"); //ロケール(地域)を設定する。
 
FILE* fp = fopen( "test1.txt", "r, ccs = UTF-8"); // ここを読み取りモード"r"にするのを忘れないように
if (fp == NULL) {
wprintf(L"ファイルを開けませんでした。\n");
return 1;
}
else {
wprintf(L"ファイルをオープンしました。\n");
}
 
 
wchar_t str1[150];
wprintf(L"文字列を読み取っています。\n");
 
fwscanf(fp, L"%s", str1);
 
wprintf(L"ファイルに書いてある文字列\n");
wprintf(L"\n");
wprintf(L"%s\n", str1);
wprintf(L"\n");
 
fclose(fp);
wprintf(L"ファイルをクローズしました。\n");
return 0;
}
</syntaxhighlight>
 
 
;実行結果
<pre>
ファイルをオープンしました。
文字列を読み取っています。
ファイルに書いてある文字列
 
これはテストです。
 
ファイルをクローズしました。
</pre>
 
 
なお、テキストファイルの拡張子に「.txt」とあるので、もしかしたらLinuxの種類によってはWindowsのShift-JISコードだと判断してLinuxが自動的にそのテキストファイルのエンコードをShift-JISに書き換える可能性があるので、もしも、上記のコードで実行しても文字化けなどしてるなら、再度、テキストファイルを開いて、UTF-8にエンコードしなおす事。
 
 
なお、Linuxでよく標準的に付属してくる glibc には、fopenのワイド文字バージョン( wfopen のような関数)は無い。
 
また、fopenで読み取るファイルに日本語を使うと、文字化けをしたり、ファイルを開くのに失敗したりする。
 
たとえば、「テスト1.txt」のような日本語のファイル名で作られたファイルは、上記のコードのfopenで読み取るファイル名を「テスト1.txt」に書き換えても、読み取りできない。
 
 
なお、Linuxでは、文字の変換には [[w:iconv]](アイコンブ) などのAPIが利用されている。iconv については高度すぎる話題になるので、説明を省略する。
 
 
 
上記コードのようにLinuxでもwprintfなどのワイド文字型の組み込み関数が使えるが、しかし、printfなどでも日本語を表示できてしまうので、Linuxではワイド文字用の組み込み関数は、実用性は乏しい。
 
=== Windowsの場合 ===
Unicodeなどのテキストファイルを読み取れるように、上記のようにワイド文字型の関数を使ってコードを書いても、日本語を含むファイルは文字化けをする。(いっぽう、テキストファイル中の英数字だけ、正しく表示されたりする。)
 
例えば、下記のようなコードを書いても、日本語の文字は、文字化けしてしまう。
 
<syntaxhighlight lang="C">
// 文字化けしてしまう。
// Windowsを想定
 
#include <stdio.h>
#include <locale.h>
 
#pragma warning(disable:4996)
 
int main()
{
_wsetlocale(LC_ALL, L""); //ロケール(地域)を設定する。
 
FILE* fp = _wfopen( L"test1.txt", L"r, ccs = UNICODE");
if (fp == NULL) { // ここを読み取りモード"r"にするのを忘れないように
wprintf(L"ファイルを開けませんでした。\n");
perror(0);
return 1;
}
else {
wprintf(L"ファイルをオープンしました。\n");
}
 
 
wchar_t str1[150];
wprintf(L"文字列を読み取っています。\n");
 
fwscanf(fp, L"%s", str1);
 
wprintf(L"ファイルに書いてある文字列\n");
wprintf(L"\n");
wprintf(L"%s\n", str1);
wprintf(L"\n");
 
fclose(fp);
wprintf(L"ファイルをクローズしました。\n");
}
</syntaxhighlight>
 
 
いっぽう、テキストファイルにANSIエンコードを使い、ソースコードの文字表示にprintfなど非ワイド型の関数を使った場合では文字化けをしない。
 
よってWindowsでは、なるべくANSIエンコードを使うのが安全だろう。特別な理由がないかぎり、ワイド文字型を使う必要も無い。
 
 
また、このことから、Windowsの自称する「Unicode」が、実際の国際規格とは実態が違っていることが分かる。
 
== バイナリーファイルの読み書き ==