当前位置: 首页 > 工具软件 > MinTTY > 使用案例 >

mintty运行windows本地程序时输入输出的缓冲问题

子车心思
2023-12-01

printf函数的输出缓冲问题

问题描述

printf函数使用了行缓冲,只有输出了换行符才刷新输出。但如果需要读取用户输入,同样会刷新stdout的输出缓冲,而不论是否有换行。

// 输入整数 a,输出a的平方
#include <stdio.h>
int main(void){
    int a;
    printf("input a:");
    scanf("%d", &a);
    printf("%d*%d=%d\n", a, a, a*a);
}
# gcc编译生成windows原生程序;mintty 下运行
$ gcc -dumpmachine
x86_64-w64-mingw32
$ make test3
gcc --std=c11 -Wall -O2    -c -o test3.o test3.c
gcc   test3.o   -o test3
$ ./test3
12
input a:12*12=144

在cmd下运行就可以

F:\test>test3.exe
input a:13
13*13=169

printf()后添加一条fflush()语句刷新输出可以解决问题;
手动关闭标准输出的缓冲setvbuf(stdout, NULL)也可以解决问题;
经过试验,是 mintty 这个模拟终端在运行Windows本地应用时,标准输出的行缓冲变成了全缓冲(即使用setvbuf函数设置为行缓冲也仍然是全缓冲;为什么会这样,我也不知道)。
为了验证,使用无缓冲io直接向标准输出打印数据,结果表明确实是输出被缓冲了。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define N 32000
char buf[N];
int main(void)
{
    // setvbuf(stdout, NULL, N, _IOLBF);
    // setbuf(stdin, NULL);
    // windows 程序在 MSYS 下是全缓冲的;标准输入和标准输出都是全缓冲
    for (int i = 0;i<5 && fgets(buf, N, stdin);i++){
        write(STDOUT_FILENO, "==>", 3);
        write(STDOUT_FILENO, buf, strlen(buf));
        write(STDOUT_FILENO, " ", 1);

        printf("->");
        fputs(buf, stdout); //
    }
}
$ ./test
a
==>a
b
==>b
3
==>3
4
==>4
5 hhh
==>5 hhh
->a
->b
->3
->4
->5 hhh

这个试验表明,标准输出功能正常,是行缓冲;但标准输入却成了全缓冲。

找到资料了

windows的终端和Linux的终端使用不同的方式处理输入输出,所以在mintty运行windows本地程序时的时候会把程序的输入输出接到管道中,做一遍过滤。副作用就是会使本地windows程序对当前终端环境产生误判。解决方案是使用winpty命令执行windows程序。

$ pacmsn -S msys/winpty
$ winpty ./test3
input a:123
123*123=15129

世界终于清静了。
PS:winpty也有点小瑕疵,比如彩色字符会搞乱输出。
参考: https://github.com/msys2/msys2/wiki/Porting

ISO C对于缓冲的规定

  1. 当且仅当标准输入和标准输出不指向交互式设备时,它们才是全缓冲的
  2. stderr 不能是全缓冲的
  3. 并没有说明stderr是不缓冲还是行缓冲;stdin和stdout指向交互式设备时是不缓冲还是行缓冲。
    许多系统的选择是:标准错误不缓冲;标准输入输出直向终端时行缓冲,指向其它设备全缓冲。
    标准I/O库不对字符进行行缓冲(???)。

2. 用 Ctrl-D模拟文件尾,没有效果

 类似资料: