繁体   English   中英

当这个程序在Windows上运行时,为什么回车会进入?

[英]Why does a carriage return creep in when this program runs on Windows?

我编写了以下程序将hexstring转换为相应的二进制数据。

#include <stdio.h>
#include <stdlib.h>

int main(void) {

  char bf[3];
  char b; /* each byte */

  bf[0] = bf[1] = bf[2] = 0;

  for (;;) {
    for (;;) { 
      bf[0] = getchar();
      if (isspace(bf[0])) continue;
      if (bf[0] == EOF) goto end;
      break;
    }

    for (;;) { 
      bf[1] = getchar();
      if (isspace(bf[1])) continue;
      if (bf[1] == EOF) goto end;
      break;
    }

    b = strtoul(bf, NULL, 16);
    //printf("%s = %d\n", bf, b);
    fwrite(&b, sizeof b, 1, stdout);
  }

 end:
  exit(0);
}

这是一个测试文件:

%cat test.txt
E244050BF817B01D5E271F90052E0DD0
A9A5D1A2468E6908D4CF9951FC544A7B
0A5DF5692545A8856F3EF2CA5440A365
0FE4C9BC9854B042514E4805F0D0C4FF

这是在UNIX系统上运行(按预期完美输出):

%./hex2bin < /mnt/test.txt | od -t x1
0000000 e2 44 05 0b f8 17 b0 1d 5e 27 1f 90 05 2e 0d d0
0000020 a9 a5 d1 a2 46 8e 69 08 d4 cf 99 51 fc 54 4a 7b
0000040 0a 5d f5 69 25 45 a8 85 6f 3e f2 ca 54 40 a3 65
0000060 0f e4 c9 bc 98 54 b0 42 51 4e 48 05 f0 d0 c4 ff
0000100

这是Windows系统上的一个运行(回车在字节7b之后爬行):

%./hex2bin.exe < test.txt | od -t x1
0000000 e2 44 05 0b f8 17 b0 1d 5e 27 1f 90 05 2e 0d d0
0000020 a9 a5 d1 a2 46 8e 69 08 d4 cf 99 51 fc 54 4a 7b
0000040 0d 0a 5d f5 69 25 45 a8 85 6f 3e f2 ca 54 40 a3
0000060 65 0f e4 c9 bc 98 54 b0 42 51 4e 48 05 f0 d0 c4
0000100 ff
0000101
%

正确的顺序应该是[...] 7b 0a [...],但它出现为[...] 7b 0d 0a [...]。 这里发生了什么事?

Windows文本文件使用字节序列0D 0A来标记行的结尾(Unix仅使用单个字节,0A)。 C标准库在此外部编码和C使用的内部“虚拟换行符”( '\\n' )之间进行转换。

也就是说,当在Windows上运行的C程序将'\\n'写入文本流时,它会被转换为0D 0A。 反向操作发生在输入上。 因为'\\n'是一个真正的char值(通常是10 ),所以其他字节可能被误解为'\\n'

如果您不想要这种行为(例如,因为您正在编写或读取二进制数据,而不是文本),则需要使用二进制流,而不是文本流。

对于普通文件,这很简单:只需在调用fopen时将"b"添加到打开模式。 对于预定义的流( stdin / stdout / stderr ),据我所知,没有可移植的解决方案,但Windows有一个额外的功能,可以将现有的流放入二进制模式; 看看这个答案

它显示了相当于以下代码的内容(也见于Microsoft官方文档中 ):

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

...
_setmode( _fileno( stdout ), _O_BINARY );

您的代码中存在一些错误:

  bf[0] = getchar();
  if (isspace(bf[0])) continue;
  if (bf[0] == EOF) goto end;

因为bf[0]char所以两个if条件都被破坏了。 char不足以存储EOF ,这是getchar返回的特殊非字符值,用于指示错误或文件结束。 通常, getchar将为成功输入返回非负值,并在出错时返回负值( EOF ,通常为-1 )。 通过将此值分配给char ,您将截断EOF并将其映射到某个实际字符值。

bf[0] == EOF检查的行为取决于char是否是您平台上的签名类型(可能是)。 如果是这样,它会使一些其他字符(通常为255,对应于ISO-8859-1中的corresponds)混淆为文件结尾。 如果char是无符号的,则此条件永远不会成立,因此您将获得无限循环。

类似地,如果char是有符号类型,则isspace(bf[0])被破坏,因为如果它们的参数不适合unsigned char所有的is...函数都有未定义的行为(有一个特殊的例外:允许EOF )。

修复是首先将getchar的结果存储在int

  int c = getchar();
  if (c == EOF) goto end;
  if (isspace(c)) continue;
  bf[0] = c;
  break;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM