Windows環境で書かれたC言語のプログラムをレビューする1機会があり、そこでファイル入出力に関しての面白い知見が得られたので記録を残しておく。
前提
- 筆者自身はMacユーザであり、Windowsには明るくない
環境
- Parallels Desktop 15上の仮想環境として動作させたWindows 10 Pro (Ver. 1909)
- MSYS2 (20200602.0.0)
- Cygwin (3.1.5)
- 上記2つはchocolatey経由でインストール
TL;DR
MinGWはWindows環境の実装としてファイル入出力時にテキストモードとバイナリモードを区別する一方で、CygwinはLinux環境の再現としてファイル入出力時に2つのモードを区別しない。
ファイル入出力時の動作の違い
- 検証用のコード
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
int count = 0;
char c;
FILE *fp;
int binary_mode = 0;
if (argc > 1 && strcmp(argv[1], "-b") == 0) {
binary_mode++; // "-b"オプションでバイナリモードでのファイル読み込みを指定
}
int i;
for (i = 1 + binary_mode; i < argc; i++) {
if ((fp = fopen(argv[i], (binary_mode > 0) ? "rb" : "r")) == NULL) {
printf("Error reading file");
return 1;
}
count = 0;
while ((c = fgetc(fp)) != EOF) {
count++;
if (c == '\r') {
printf("%6d: <CR>\n", count);
} else if (c == '\n') {
printf("%6d: <LF>\n", count);
} else {
printf("%6d: %c\n", count, c);
}
}
fclose(fp);
printf("[%s] contains %d characters\n", argv[i], count);
}
return 0;
}
- 検証用ファイル
<CR>
はキャリッジリターン(0x0D)、<LF>
はラインフィード(0x0A)を表す。
CR<CR>
LF<LF>
CRLF<CR><LF>
MinGW(MSYS2)上の挙動
$ gcc -o test-mingw test.c
$ ./test-mingw.exe cr.txt lf.txt crlf.txt
1: C
2: R
3: <CR>
[cr.txt] contains 3 characters
1: L
2: F
3: <LF>
[lf.txt] contains 3 characters
1: C
2: R
3: L
4: F
5: <LF>
[crlf.txt] contains 5 characters
$ ./test-mingw.exe -b cr.txt lf.txt crlf.txt
1: C
2: R
3: <CR>
[cr.txt] contains 3 characters
1: L
2: F
3: <LF>
[lf.txt] contains 3 characters
1: C
2: R
3: L
4: F
5: <CR>
6: <LF>
[crlf.txt] contains 6 characters
MinGWではファイル読み込みにテキストモードを指定した場合とバイナリモードを指定した場合で結果が異なる。
テキストモードを指定した場合、<CR>
単体や<LF>
単体はそのまま1文字として読み込まれる一方で、<CR><LF>
は<LF>
1文字に変換されて読み込まれる。
Cygwin上の挙動
$ gcc -o test-cygwin test.c
$ ./test-cygwin.exe cr.txt lf.txt crlf.txt
1: C
2: R
3: <CR>
[cr.txt] contains 3 characters
1: L
2: F
3: <LF>
[lf.txt] contains 3 characters
1: C
2: R
3: L
4: F
5: <CR>
6: <LF>
[crlf.txt] contains 6 characters
$ ./test-cygwin.exe -b cr.txt lf.txt crlf.txt
1: C
2: R
3: <CR>
[cr.txt] contains 3 characters
1: L
2: F
3: <LF>
[lf.txt] contains 3 characters
1: C
2: R
3: L
4: F
5: <CR>
6: <LF>
[crlf.txt] contains 6 characters
テキストモードかバイナリモードかにかかわらず、1バイト単位で文字が読み込まれる。
MinGWとCygwinの設計思想
MinGWのWebサイトには以下の記述がある:
MinGW, a contraction of "Minimalist GNU for Windows", is a minimalist development environment for native Microsoft Windows applications.
(中略)
MinGW, being Minimalist, does not, and never will, attempt to provide a POSIX runtime environment for POSIX application deployment on MS-Windows.
つまり、MinGWはあくまでもWindowsネイティブアプリケーションのための開発環境を提供しているため、Windows特有のファイルモードに対応しているといえる。
一方で、CygwinのWebサイトには以下の記述がある:
Cygwin is:
- a large collection of GNU and Open Source tools which provide functionality similar to a Linux distribution on Windows.
したがって、CygwinはLinux環境をWindows上で再現するものであるため、Windows特有のファイルモードに対応せずにLinux環境同様すべてのファイルを一元的に扱っているといえる。
参考文献
-
要はTAとして採点作業しただけである。ものは言いよう。 ↩