为什么 fread(fmtChunkId, sizeof(char), 4, fp);读11个字符?

Why does fread(fmtChunkId, sizeof(char), 4, fp); read 11 characters?

这是我遇到问题的代码部分:

fread(fmtChunkId, sizeof(char), 4, fp);
if(strcmp(fmtChunkId, "WAVE") != 0) {
    cout << "Not WAVE format: " << fmtChunkId << endl;
    return 0;
}

当我 运行 程序时,它打印 Not WAVE format: WAVE    e∞@ ,它有 11 个字符长,而不是 4 个字符。但是,当我将 fmtChunkId 替换为 type 时,它可以正常工作,这让我感到困惑,因为我将这两个变量声明为相同。

#include <iostream>
#include <string.h>
using namespace std;

int main() {
    /*Get file path*/
    char filepath[261];
    cout << "Please enter the file path of a .wav file: ";
    cin.getline(filepath, sizeof(filepath));
    FILE *fp = NULL;
    fp = fopen(filepath, "rb");
    if(!fp) {
        cout << "Failed to open file: " << filepath;
        return 0;
    }
    cout << endl;

    /*Declarations*/
    char type[4];
    char riffChunkId[4];
    int riffChunkSize;
    char fmtChunkId[4];
    int fmtChunkSize;
    short audioFormat;
    short numChannels;
    int sampleRate;
    int byteRate;
    short blockAlign;
    short bitsPerSample;
    int dataSize;

    /*Read file data*/
    fread(riffChunkId, sizeof(char), 4, fp);
    if(strcmp(riffChunkId, "RIFF") != 0) {
        cout << "Not RIFF format: " << riffChunkId << endl;
        return 0;
    }
    fread(&riffChunkSize, sizeof(int), 1, fp);
    fread(fmtChunkId, sizeof(char), 4, fp);
    if(strcmp(fmtChunkId, "WAVE") != 0) {
        cout << "Not WAVE format: " << fmtChunkId << endl;
        return 0;
    }
    fread(type, sizeof(char), 4, fp);
    if(strcmp(type, "fmt ") != 0) {
        cout << "Not fmt: " << type << endl;
        return 0;
    }
    fread(&fmtChunkSize, sizeof(int), 1, fp);
    fread(&audioFormat, sizeof(short), 1, fp);
    fread(&numChannels, sizeof(short), 1, fp);
    fread(&sampleRate, sizeof(int), 1, fp);
    fread(&byteRate, sizeof(int), 1, fp);
    fread(&blockAlign, sizeof(short), 1, fp);
    fread(&bitsPerSample, sizeof(short), 1, fp);
    fread(type, sizeof(char), 4, fp);
    if(strcmp(type, "data") != 0) {
        cout << "Not data: " << type << endl;
        return 0;
    }
    fread(&dataSize, sizeof(int), 1, fp);

    /*Print file data*/
    cout << "RIFF Chunk Size: " << riffChunkSize << endl;
    cout << "fmt Chunk Size: " << fmtChunkSize << endl;
    cout << "Audio Format: " << audioFormat << endl;
    cout << "Number of Channels: " << numChannels << endl;
    cout << "Sample Rate: " << sampleRate << endl;
    cout << "byteRate: " << byteRate << endl;
    cout << "blockAlign: " << blockAlign << endl;
    cout << "Bits Per Sample: " << bitsPerSample << endl << endl;

    return 0;
}

字符串文字 "WAVE" 实际上是 5 个字节长,因为 C 风格的字符串必须以空字符 [=12=] 结尾。由于您声明 typefmtChunkId 只有 4 个字符,因此 strcmp 函数和 cout << 语句实际上会继续读取超过 4 个字节的末尾,直到它遇到 [=12 =]. (如果它在进入未经授权的内存之前没有命中 [=12=],这可能会导致段错误)。

因此,对于 fmtChunkId,它会打印出一些额外的垃圾字符,因为这是它在下一个 [=12=] 之前在内存中找到的内容。对于 type,下一个字节恰好是 [=12=],所以它意外地工作了。

正如其他评论者提到的,一个解决方案是将字符串初始化为 5 的长度,并在 fread 之后但在 strcmp.

之前将最后一个字节设置为 0

一个更eloquent的解决方案是使用memcmp,它直接比较字节(这是你真正想要的)而不是字符串:

fread(fmtChunkId, sizeof(char), 4, fp);
if(memcmp(fmtChunkId, "WAVE", 4) != 0) {
    cout << "Not WAVE format" << endl;
    return 0;
}