c - 必须使用 `%.4s` 的精度修饰符才能显示 `char[4]` ,为什么简单的 `%s` 不能正常工作?

标签 c arrays audio wav modifiers

我有以下代码(仅发布必要的行)。 这里我复制了 WAVE 文件的前 44 个字节(PCM,即线性量化)。 问题在于显示 struct 的 char[4] 记录。

无法弄清楚,虽然试图了解原因但没有结果。

问题:为什么我必须使用精度修饰符 %.*s 来仅显示 char[N] 的前 4 个符号仅使用 %s 打印 char[4] 变量?

BUT 如果我将修饰符写入 %s --> %.4sprintf() 函数正确打印所有内容:“RIFF”、“WAVE”、“fmt”、“data”。 它仅显示每个 char[4] 记录的前 4 个符号。但是未显示的符号又如何呢?

我通过 %s 得到以下信息:

Enter input and output filenames (with no extension):
europe_-_final_countdown
europe_-_final_countdown_out
Opening file: "europe_-_final_countdown.wav" has been successfully opened.

*********************************
       ChunkID: RIFF4?AWAVEfmt     // instead of "RIFF"
     ChunkSize: 54629940
        Format: WAVEfmt            // instead of "WAVE"
   SubChunk1ID: fmt                // here is "fmt " -> ok
 SubChunk1Size: 16
   AudioFormat: 1
   NumChannels: 2
    SampleRate: 44100
      ByteRate: 176400
    BlockAlign: 4
 BitsPerSample: 16
   SubChunk2ID: data?A             // instead of "data"
 SubChunk2Size: 54629904
*********************************
Process returned 0 (0x0)   execution time : 34.554 s
Press ENTER to continue.

所以这是代码:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MAX_NAME_LENGTH 255

typedef unsigned short byte2;
typedef unsigned int   byte4;

struct header
{
    // totally 44 bytes;        endian (all the rest are little)
    // RIFF
    char    ChunkID[4];         // big
    byte4   ChunkSize;
    char    Format[4];          // big
    // fmt
    char    SubChunk1ID[4];     // big
    byte4   SubChunk1Size;
    byte2   AudioFormat;
    byte2   NumChannels;
    byte4   SampleRate;
    byte4   ByteRate;
    byte2   BlockAlign;
    byte2   BitsPerSample;
    // data
    char    SubChunk2ID[4];     // big
    byte4   SubChunk2Size;
};

struct header hdr;



int main()
{
    char nameInput[MAX_NAME_LENGTH];
    char nameOutput[MAX_NAME_LENGTH];
    printf("Enter input and output filenames (with no extension):\n");

    scanf("%s", nameInput);
    strcat(nameInput, ".wav");
    //printf("nameInput: %s", nameInput);

    scanf ("%s", nameOutput);
    strcat(nameOutput, ".wav");
    //printf("nameInput: %s", nameOutput);

    /// Opening the input file.
    FILE *input = fopen(nameInput, "rb");
    if (input == NULL)
    {
        printf ("Opening file: Couldn’t open file %s; %s.\n",
                 nameInput, strerror (errno));
        exit (EXIT_FAILURE);
    }
    else
        printf("Opening file: \"%s\" has been successfully opened.\n",
                nameInput);


    /// copying header (first 44 bytes) to `hdr`
    char buf[44];
    fread(&hdr, 1, sizeof(buf), input);


    /// hdr
    printf("\n*********************************\n");
    printf("       ChunkID: %s\n",     hdr.ChunkID   );         // Contains the letters "RIFF" in ASCII.
    printf("     ChunkSize: %d\n",     hdr.ChunkSize );         // 36 + SubChunk2Size (which we don't mention)
    printf("        Format: %s\n",     hdr.Format    );         // Contains the letters "WAVE"
    printf("   SubChunk1ID: %s\n",     hdr.SubChunk1ID   );  // Contains the letters "fmt "
    printf(" SubChunk1Size: %d\n",     hdr.SubChunk1Size );  // 16 for PCM.  This is the size of the rest of the Subchunk which follows this number.
    printf("   AudioFormat: %d\n",     hdr.AudioFormat   );  // PCM = 1 (i.e. Linear quantization). Values other than 1 indicate some form of compression.
    printf("   NumChannels: %d\n",     hdr.NumChannels   );  // Mono = 1, Stereo = 2, etc.
    printf("    SampleRate: %d\n",     hdr.SampleRate    );  // 8000, 44100, etc.
    printf("      ByteRate: %d\n",     hdr.ByteRate      );  // == SampleRate * NumChannels * BitsPerSample/8
    printf("    BlockAlign: %d\n",     hdr.BlockAlign    );  // == NumChannels * BitsPerSample/8. The number of bytes for one sample including all channels.
    printf(" BitsPerSample: %d\n",     hdr.BitsPerSample );  // 8 bits = 8, 16 bits = 16, etc.
    printf("   SubChunk2ID: %s\n",     hdr.SubChunk2ID);
    printf(" SubChunk2Size: %d\n",     hdr.SubChunk2Size);
    printf("\n*********************************\n");

    /// ...
    return 0;
}

最佳答案

%s 格式说明符导致 printf 打印以 null 结尾的字符串。您的字符串不是以 null 结尾的。

printf 尝试打印以 null 结尾的字符串时,它只会打印字符,直到遇到零字节为止。在您的情况下,这会导致字符串预期结尾之后的数据被解释为字符并打印,直到遇到零字节。

关于c - 必须使用 `%.4s` 的精度修饰符才能显示 `char[4]` ,为什么简单的 `%s` 不能正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24794497/

相关文章:

c - 调用 execv() 时动态分配的内存会发生什么?

带有数组的 C# 结构

arrays - TypeScript 对象作为 C# 中的字典类型

javascript - 检查所有数组是否有值且不为空

Android:播放声音文件的一部分

c - 在 C 语言中使用 rand( ) 生成随机整数序列

模拟调度程序的 C 程序

haskell - 使用 Haskell 从麦克风捕获音频输入?

audio - 将音频文件重新采样到不是原始速率的因素或从低到高的速率如何工作?

C: TCP 服务器没有收到整个消息