繁体   English   中英

为什么在每个fread()中,printf(“%s”,charstr)越来越多地打印超出预期的内容?

[英]Why does printf(“%s”,charstr) increasingly prints more than expected with each fread()?

为了尝试学习文件结构,我试图读取.wav文件并仅打印有关该文件的信息。 我有一个结构,它包含所有定义为以下内容的信息:

typedef struct{
   char chunkId[4];
   unsigned int chunkSize;
   char format[4];
   char subchunk1Id[4];
   unsigned int subchunk1Size;
   unsigned short audioFormat;
   unsigned short numChannels;
   unsigned int sampleRate;
   unsigned int byteRate;
   unsigned short blockAlign;
   unsigned short bitsPerSample;
   char subchunk2Id[4];
   unsigned int subchunk2Size;
   void *data;
} WavFile;

发生了什么事是每个我时间fread通过文件,它会导致我的C字符串来打印长。 这是一个示例代码片段:

   fseek(file, SEEK_SET, 0);
   fread(wavFile.chunkId, 1, sizeof(wavFile.chunkId), file);
   fread(&wavFile.chunkSize, 1, sizeof(wavFile.chunkSize), file);
   fread(wavFile.format, 1,sizeof(wavFile.format), file);  
   fread(wavFile.subchunk1Id, 1, sizeof(wavFile.subchunk1Id), file);
   fread(&wavFile.subchunk1Size, 1, sizeof(wavFile.subchunk1Size), file);
   fread(&wavFile.audioFormat, 1, sizeof(wavFile.audioFormat), file);

   printf("%s\n",wavFile.chunkId);
   printf("%d\n",wavFile.chunkSize);
   printf("%s\n",wavFile.format);
   printf("%s\n",wavFile.subchunk1Id);
   printf("%d\n",wavFile.subchunk1Size);
   printf("%d\n",wavFile.audioFormat);

我进行struct设置的方式,读取文件的方式或printf()查看字符串的方式都导致输出显示,如下所示:

RIFF�WAVEfmt 
79174602
WAVEfmt 
fmt 
16
1

预期输出:

RIFF
79174602
WAVE
fmt
16
1

我确实知道c字符串需要以null终止,但是后来我开始思考如何从二进制文件中打印字符串与打印类似printf("test");的字符串文字有何不同printf("test"); 文件规范要求成员的大小必须具有在我的struct定义的确切大小。 正在做char chunkId[5]; 然后chunkId[4]='\\0'; 似乎不是解决此问题的好方法。

我已经尝试解决这一问题了几天,所以现在我来SO也许是朝着正确的方向推进。

为了全面披露,这是文件相关部分的十六进制输出,因为此Web表单并未显示出我的输出中出现的所有乱码。

52 49 46 46 CA 1B B8 04 57 41 56 45 66 6D 74 20 10 00 00 00 01 00 02 00 44 AC 00 00 98 09 04 00 06 00 18 00 64 61 74 61

如果知道大小,则可以限制printf的输出:

// Only prints 4-bytes from format.  No NULL-terminator needed.
printf("%.4s\n", wavFile.format);

如果大小存储在其他字段中,则也可以使用该大小:

// The * says: print number of chars, as dictated by "theSize"
printf("%.*s\n", wavFile.theSize, wavFile.format);  

您调用printf() ,它期望以'\\0'结尾的字符串,但是您的struct元素不是( fread()不会添加'\\0'formatchunkId等没有足够的长度包含它)。

最简单的方法是:

 printf( "%.*s\n", (int)sizeof(wavFile.format), wavFile.format );

如果它不是以null结尾的字符串 ,则可以使用.*和一个额外的int参数,该参数指定printf的字符串大小,例如:

 printf("%.*s\n", (int)sizeof(wavFile.chunkId), wavFile.chunkId);

或者:

 printf("%.4s\n", wavFile.chunkId);

由于大小似乎是固定的,因此您的情况可能更简单。

从上面的printf文档中,格式字符串中的精度说明符的工作方式如下:

(可选的) 。 后跟整数或*,表示转换的精度。 在使用*的情况下,精度由int类型的附加参数指定。 如果此参数的值为负,则将其忽略。 有关精度的确切影响,请参见下表。

文本所引用的表格的字符串如下:

精度指定要写入的最大字节数。

首先,请确保您正在以二进制模式读取文件(在模式设置为"rb"的情况下使用fopen )。 在类似Unix的系统上,这没有什么区别,但是在其他以文本模式读取二进制文件的系统上,数据可能会损坏。 并且您应该检查每个fread()调用返回的值; 不要仅仅假设一切正常。

%s格式的printf需要指向字符串的指针。 字符串始终以空字符'\\0'标记结尾。

如果您从文件中读取了大块数据,则不可能有终止的空字符。

就像其他答案所说的那样, %s格式有一些变化,可以限制打印字符的数量,但即使这样, printf也不会打印碰巧出现在数组中的第一个空字符之后的任何内容。 (一个空字符,它只是一个值为0的字节,可能是有效数据,并且之后可能还有更多有效数据。)

要打印已知长度的任意字符数据,请使用fwrite

fwrite(wavFile.chunkId, sizeof wavFile.chunkId, 1, stdout);
putchar('\n');

在这种情况下,您似乎希望chunkId包含可打印的字符; 在您的示例中,它具有"RIFF" (但没有尾随的空字符)。 但是您可能正在读取无效的文件。

并且将二进制数据打印到标准输出可能会出现问题。 如果它恰好由可打印的字符组成,那很好,您可以假定所有内容都可以在初始版本中打印。 但是您可能会考虑检查数组中的字符是否实际上是可打印的(请参见isprint() ),如果不是,则以十六进制打印它们的值。

暂无
暂无

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

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