【问题标题】:msvc compiled programs output differently under cygwin ttycygwin tty下msvc编译的程序输出不同
【发布时间】:2021-09-23 15:20:20
【问题描述】:

在 Cygwin 下:如何阻止 msvc 编译程序的输出在 tty 中被转码。

在 Cygwin 下:gcc 与 msvc 编译的程序在 tty 下的运行似乎彼此不同。具体来说,当设置了字符的第 8 位时,我在 tty 下看到仅来自 msvc 生成的二进制输出的一些奇怪的字符集转换。我真的很想知道如何关闭这种烦人的行为。考虑:

screen-cap of terminal output (duplicated in a code quote below)

! pwd
/tmp/demo_dir
! echo $LC_ALL "," $LANG "," $LC_CTYPE
, ,
! ./compiled_with_gcc.exe | hexdump
0000000 cece cece
0000004
! ./compiled_with_msvc.exe | hexdump
0000000 cece cece
0000004
! ./compiled_with_gcc.exe
▒▒▒▒!
! ./compiled_with_msvc.exe
╬╬╬╬!

问题是最后一行。 msvc 编译版本的输出与预期不符。上面演示了这两个程序输出相同的数据:所以最后两个输出应该是相同的。但是 tty 版本(没有管道)仅在 msvc 情况下发生更改。 gcc 编译的程序输出通过 tty 毫发无损。此处显示的输出来自 cygwin 终端,但我在 xterm 中看到完全相同的输出差异。

我相信它发生在 tty 而不是终端:因为我用 C 编写了一个独立的 cygwin 程序,它运行 gcc 和 msvc 编译的程序,无论是在管道下还是在未连接到终端的 tty 下.该程序记录从 tty 接收到的实际字节。 当运行 gcc 编译的一个时,tty 会按预期给出 '0xce' 字节。 但是,当通过相同的 tty 收听 msvc 编译程序时,会从 msvc 编译程序接收到一系列“0x8ec3”模式。 当使用管道而不是 tty 时,它们都输出 '0xce'。

这表明 msvc 编译程序通过 tty 输出的宽度增加了。鉴于 cygwin 对 UTF-8 的偏好:很容易怀疑这里出了问题,并且 cygwin 导致了 gcc 编译程序不会发生的额外转码。我希望将其关闭...如何在今天的 cygwin 中成功禁用 UTF-8 翻译。

我注意到,对于通过 tty 访问的 msvc 编译的二进制文件,似乎不尊重 LC_ALL 来阻止这种情况的发生。甚至当 C 程序以 setlocale(0,""); 开头时

生成输出的程序(将使用两个编译器交替编译以进行测试)与您期望的完全一样。两种情况下使用相同的 C 源。它只是调用 printf 或写入一些字节。 msvc版本使用Visual Studio 2019 cl.exe编译(全部运行在Windows10上)。

复制:


#ifndef __CYGWIN__
#include <windows.h>
#else
#include <unistd.h>
#endif

#include <io.h>
#include <fcntl.h>
#include <locale.h>

int main()
{
    if(!setlocale(LC_ALL, "")) {
        return 77;    //historically: non-filesystem permission-denied exit-code
    }

#ifndef __CYGWIN__
    //Irrelevent: But avoids stackexchange users asking for it.
    _setmode(1,_O_BINARY);
    _set_fmode(_O_BINARY);
#endif

    char *dat="\316\316\316\316";
    write(1,dat,4);     // printf/fflush here gives same results.
    return 0;
}
@echo off

:: ugly msvc build script. ms_cl.bat
:: full of M$ hardcoded paths. Likely includes some unused libraries.

:: Load compilation environment
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat"

:: Invoke compiler with any options passed to this batch file
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\cl.exe" /std:c17 %* kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
Build msvc version with:
! ms_cl.bat code.c
Run in terminal with:
! ./code.exe | hexdump
! ./code.exe

Build gcc version with:
! gcc code.c
Run in terminal with:
! ./a.exe | hexdump
! ./a.exe

请注意,相同的程序在十六进制中具有相同的输出,但输出转码的方式不同。在我的用例中,msvc 是“错误的”。

显然,我怀疑 M$ 正在做一些翻译:所以我尝试了 _fmode setmode() 和更多的每种组合来设置二进制模式。我怀疑某些 cygwin UTF-8 检测失败的情况,因此尝试将 LC_ALL 等设置为纯“C”模式并在 shell 中导出。我同样尝试在 msvc 源中设置语言环境。

Cygwin 做了很多工作来在 windows 下创建一个类似 unix 的环境。鉴于上面的 hexdumps,我只能猜测 Cygwin(或一些隐藏的 msvc 控制台层)在这里做了一些非常专业的事情并妨碍了我。这可能与 cygwin 迁移到 ConPty 有关。无论哪种方式。我想帮忙把它关掉。

【问题讨论】:

标签: c visual-c++ cygwin tty


【解决方案1】:

OP:已经有一段时间了。问题中提出的问题目前仍未解决。但是,我从行星黑客中发现了一个 hacky hack hack,它允许在不解决问题的情况下避免问题。我将这个无答案的问题避免黑客作为答案发布,并将(最终)将其标记为解决方案。但前提是找不到问题的实际解决方案。

为了避免 msvc 编译程序的输出在 tty 中被转码:首先将 msvc 编译程序的输出通过管道传输到一个简单重复它的 gcc 编译程序(例如 'cat' 或 'tail -f' ) 并将 gcc 编译的程序连接到 tty。

这通过将 msvc 案例与 tty 分开来隐藏在 msvc 案例中发生的任何事情。然后尊重环境。 tty 只知道它连接到一个 gcc 编译的程序 - 并且工作正常。

! ./compiled_with_gcc.exe        # gcc_compiled->tty  = good
▒▒▒▒!
! ./compiled_with_msvc.exe       # msvc_compiled->tty = bad
╬╬╬╬!
! ./compiled_with_msvc.exe|cat   # msvc_compiled->gcc_compiled->tty = hacky but good
▒▒▒▒!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多