您好我有这个代码,用于输入一个wav文件,然后将wah标头放入一个结构中然后输出它。一切都很好除了audioFormat和numChannels但我无法理解为什么。例如它应该输出audioFormat:1和numChannels:2但它输出audioFormat:0和numChannels:1。我不明白为什么会这样。
typedef struct wavHeader
{
byte chunckID[4];
dword chunckSize;
byte format[4];
byte subchunk1ID[4];
word subchunk1Size;
word audioFormat;
word numChannels;
dword sampleRate;
dword byteRate;
word blockAlign;
word bitsPerSample;
byte subchunk2ID[4];
dword subchunk2Size;
}wav_header;
int check_file_name(char *filename);
void list(char **array) //argv
{
wav_header wavHeader;
FILE *pFile;
if(check_file_name(array[2]) == 0)
{
printf("wrong file name\n");
exit(1);
}
pFile = fopen (array[2] ,"r");
if( pFile != NULL)
{
fread(&wavHeader, sizeof(wav_header), 1, pFile);
fclose(pFile);
printf("ChunkID: %c%c%c%c\n",wavHeader.chunckID[0],wavHeader.chunckID[1],wavHeader.chunckID[2],wavHeader.chunckID[3]);
printf("ChunkSize: %d\n",wavHeader.chunckSize);
printf("Format: %c%c%c%c\n",wavHeader.format[0],wavHeader.format[1],wavHeader.format[2],wavHeader.format[3]);
printf("SubChunk1ID: %c%c%c%c\n",wavHeader.subchunk1ID[0],wavHeader.subchunk1ID[1],wavHeader.subchunk1ID[2],wavHeader.subchunk1ID[3]);
printf("Subchunk1Size: %d\n",wavHeader.subchunk1Size);
printf("AudioFormat: %d\n",wavHeader.audioFormat);
printf("NumChannels: %d\n",wavHeader.numChannels);
printf("SampleRate: %d\n",wavHeader.sampleRate);
printf("ByteRate: %d\n",wavHeader.byteRate);
printf("BlockAlign: %d\n",wavHeader.blockAlign);
printf("BitsPerSample: %d\n",wavHeader.bitsPerSample);
printf("Subchunk2ID: %c%c%c%c\n",wavHeader.subchunk2ID[0],wavHeader.subchunk2ID[1],wavHeader.subchunk2ID[2],wavHeader.subchunk2ID[3]);
printf("Subchunk2Size: %d\n",wavHeader.subchunk2Size);
}
else
{
printf("This file doesn't exit\n");
exit(1);
}
}
答案 0 :(得分:4)
原因是你的struct wavHeader
看起来并不像你认为的那样。让我解释。允许C编译器更改结构中字段的对齐方式。通常,这意味着字段以4字节或8字节边界对齐。请参阅有关C struct memory layout的讨论。
实际上你的结构可能在内存中布局了这样的东西:
Byte 1 2 3 4
+------+------+------+------+
| chunckID |
+------+------+------+------+
| chunckSize |
+------+------+------+------+
| format |
+------+------+------+------+
| subchunk1ID |
+------+------+------+------+
|subchunk1Size| ~~~~~ ~~~~~ << padding
+------+------+------+------+
| audioFormat | ~~~~~ ~~~~~ << padding
+------+------+------+------+
| numChannels | ~~~~~ ~~~~~ << padding
+------+------+------+------+
....
因此,您看到字段subchunk1Size
,audioFormat
和numChannels
不是连续的!但是,您可以使用指令#pragma pack
来强制执行您想要的布局。像这样:
#pragma pack(push, 1) // exact fit - align at byte-boundary, no padding
typedef struct wavHeader
{
byte chunckID[4];
dword chunckSize;
byte format[4];
byte subchunk1ID[4];
word subchunk1Size;
word audioFormat;
word numChannels;
dword sampleRate;
dword byteRate;
word blockAlign;
word bitsPerSample;
byte subchunk2ID[4];
dword subchunk2Size;
} wavHeader;
#pragma pack(pop)
旁注:在编写此响应时,我发现您可能还需要注意波头中多字节值的不同字节顺序。
答案 1 :(得分:2)
subchunk1Size
应该是dword
,而不是word
(例如,请参阅http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html)。您的其他块大小已正确声明。
作为djf points out,您还需要指定包装并担心字节顺序。 WAV头是16位打包和little-endian。使用gcc
,我更喜欢在结构声明之前使用#pragma pack(push, 2)
,之后使用#pragma pack(pop)
。如果您#include <endian.h>
,您可以使用le32toh
和le16toh
阅读(以及他们的同行htole32
和htole16
来撰写)。