【问题标题】:Regarding strings in printf关于 printf 中的字符串
【发布时间】:2023-04-01 03:05:02
【问题描述】:

来自这个帖子https://stackoverflow.com/a/22059317/5859944

FILE *fileptr;
char *buffer;
long filelen;

fileptr = fopen("myfile.txt", "rb");  // Open the file in binary mode
fseek(fileptr, 0, SEEK_END);          // Jump to the end of the file
filelen = ftell(fileptr);             // Get the current byte offset 
                                         in the file
rewind(fileptr);                      // Jump back to the beginning of 
                                         the file

buffer = (char *)malloc((filelen+1)*sizeof(char)); // Enough memory 
                                                      for file + \0
fread(buffer, filelen, 1, fileptr); // Read in the entire file
fclose(fileptr); // Close the file

您将文件作为字节数组读取。

很明显,它只是一个字符串。 可以添加一个

buffer[filelen] = '\0';

printf("%s" , buffer);

应该像字符串一样打印文件的全部内容。它在简单的文本文件中这样做,但不是在二进制文件中。

对于二进制文件,必须编写如下函数:

void traverse(char *string ,size_t size){
  for(size_t i=0;i<size;i++)
    printf("%c",string[i]);
}

并一个一个地打印每个字符。 这会使屏幕上出现乱码。

  • 为什么printf 不将buffer 视为二进制文件的字符串?
  • 为什么 printf 在函数 traverse 中使用乱码而不是字符?

对于第二个要点,我知道这可能是由于signed char,但即使字符串存储为unsigned char,结果仍然相同。

【问题讨论】:

  • 二进制文件通常包含零。那是\0 字符。
  • 读取文本文件作为二进制文件将使您的函数正确打印
  • 字符串以空值结尾。如果字符串中有一个 0 字节,那么就 printf 而言,这是字符串的结尾。并非所有字符都是可打印的,所以如果您的文件包含这些字符,那么您就会得到乱码。
  • 您想打印数值吗?然后看到这个:stackoverflow.com/questions/15736497/… 看起来你的问题与你真正的问题完全无关。
  • 试试printf("%c",string[i]); --> printf(" %hhu",string[i]);

标签: c printf file-handling


【解决方案1】:

为什么 printf 不将缓冲区视为二进制文件中的字符串?

printf("%s",buffer) 确实假定buffer 包含一个C 字符串。问题是,这不是 buffer 实际包含的内容。您的 buffer 实际上包含二进制文件中的字节。

C 字符串以第一个零字节(又名,'\0',又名,ASCII NUL)终止,并且任意非文本文件(又名,“二进制文件”)可以在其自身的任何位置包含零字节。 printf "%s" 格式一看到第一个零字节就会停止。

为什么函数遍历中的 printf 放的是乱码而不是字符?

那个“乱码”个字符。但是这些字符没有任何意义,因为您试图解释为字符序列的文件并不意味着以这种方式解释。

文本文件是一个字节序列,旨在根据某些character encoding进行渲染,而通常旨在传达某种人类-可读信息。任意“二进制”文件可能包含不应代表人类可读文本的字节序列。它们代表其他东西,一些计算机程序可以理解。

printf "%s" 尝试根据某些字符编码系统(通常是 UTF-8US-ASCII)呈现这些字节,但是 (a) 它并不总是能够这样做,并且 (b) 即使它能够这样做,字符序列也没有任何意义。

【讨论】:

    【解决方案2】:

    这里的第一个问题是您正在混合阅读文件的目的。要从文件中读取 二进制 数据,然后打印该二进制数据,您应该始终使用 unsigned charunsigned char* 来存储从 二进制 文件中读取的数据。

    这是因为为了获得打印数据的准确表示,您需要在printf 的格式字符串中使用"%u" 类型标志。只有some characters are printable 根据ASCII,这意味着如果您想查看文件中的所有二进制数据,如果使用"%c" 标志,您将无法看到其中的一些打印。

    你的函数的二进制版本是:

    void traverse(unsigned char *string ,size_t size){
      for(size_t i=0;i<size;i++)
        printf("%u",string[i]);
    }
    

    第二个问题是

    应该像字符串一样打印文件的全部内容。它在简单的文本文件中这样做,但不是在二进制文件中。

    这不是真的。使用"%s" 标志打印字符,就好像它们是可打印的字符一样,它会在达到空值时终止,\0 字符。您无法有效地使用%s 打印二进制数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      相关资源
      最近更新 更多