【问题标题】:This small printf loop emits one extra byte seemingly out of nowhere, why?这个小的 printf 循环似乎突然发出了一个额外的字节,为什么?
【发布时间】:2019-10-22 06:53:28
【问题描述】:

这个独立的程序,当使用 Windows 命令行(即test.exe > test.txt)运行时,由于我无法理解的原因发出一个额外的字节。

#include <stdio.h>

int main() {
    int N = 50;
    for (int i = 0; i < N; ++i)
        printf("%c%c%c", (int)(i / (float)N * 255), 0, 255);
}

人们会认为 test.txt 有 150 个字节,但它有 151 个字节。用十六进制编辑器查看它可以看到:

0000 ff05 00ff 0d0a 00ff 0f00 ff14 00ff     
1900 ff1e 00ff 2300 ff28 00ff 2d00 ff33
00ff 3800 ff3d 00ff 4200 ff47 00ff 4c00
ff51 00ff 5600 ff5b 00ff 6000 ff66 00ff
6b00 ff70 00ff 7500 ff7a 00ff 7f00 ff84
00ff 8900 ff8e 00ff 9300 ff99 00ff 9e00
ffa3 00ff a800 ffad 00ff b200 ffb7 00ff
bc00 ffc1 00ff c600 ffcc 00ff d100 ffd6
00ff db00 ffe0 00ff e500 ffea 00ff ef00
fff4 00ff f900 ff

循环的第三次迭代似乎是发出四个字节的罪魁祸首:0d0a00ff。我一生都无法弄清楚为什么会发生这种情况。我用 Visual Studio 2015 编译了这个,以防万一。

【问题讨论】:

  • 不知何故,这个输出看起来不是来自这个程序。 0d0a 是行尾组合,不能由所提供的程序产生。 更新: - 显然它可以作为答案说明......
  • stdout 是一个文本流,它会自动将 \n 转换为 \r\n。
  • @HansPassant 有没有办法关闭这个效果?
  • 似乎有三种选择可行:(1)不要使用标准输出,而是以二进制模式打开输出文件,(2)使用具有真正重定向支持的操作系统破坏数据(即 Windows 以外的任何数据),或 (3) 不要尝试重定向二进制数据,而是坚持使用文本格式。
  • 可能是freopen(NULL, "wb", stdout);?我没有密切关注the POSIX description,但乍一看它似乎可以工作。尝试将其作为main() 中的第一条语句。

标签: c printf stdio


【解决方案1】:

(int)(2 / (float)5 * 255) 是 10,这是换行符的 ASCII 表示,Windows 将其转换为其正常的 CRLF 表示。

据我所知,没有办法避免这种行为(freopen 在 Windows 上受到限制),但是看到你想写入二进制数据,使用文本格式化函数 printf 和标准输出可能不是理想的方法。

【讨论】:

  • 视窗!我花了 10 分钟繁殖,差点把头发拔掉!当然,我已经很久没有为 Windows 编写代码了……
  • 为什么要做 IO 重定向?是因为txt 扩展吗?或者它总是这样做?我们如何获得二进制流重定向?
  • 我猜 Windows 有很强的文本与数据区别。听起来这想被视为数据而不是文本。或者更好的是,不要使用 Windows。
  • @EugeneSh。它是标准输出,我想在 Windows 上标准输出是文本模式。
  • 这不是由 Windows 完成的。它是将 C 约定映射到 OS 行结尾的 C 运行时库, printf("hello world\n") 样式。 fopen() 具有模式参数的基本原因。并且 freopen() 用于将标准输出更改为二进制模式。
猜你喜欢
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
  • 2023-01-16
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多