You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言WAV音频反转代码未通过check50的问题排查

问题:WAV音频反转代码无法通过check50检测

我用C语言编写了反转WAV音频片段并生成新WAV文件的代码,实际播放音频已反转,但check50提示文件未按指定要求反转。代码逻辑为从输入文件末尾开始逐块读取音频数据写入输出文件,直到文件头位置,同时计算了每个音频块的大小。要求保持每个音频块的声道顺序,例如双声道WAV文件中,最后一个输入音频块的第一个声道需成为第一个输出音频块的第一个声道。

以下是我的代码:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "wav.h"
#include <string.h>

typedef uint8_t BYTE;

const int HEADER_SIZE = 44;

int check_format(WAVHEADER header);
int get_block_size(WAVHEADER header);

int main(int argc, char *argv[])
{
    // Ensure proper usage
    // TODO #1
    if (argc != 3)
    {
        printf("usage: ./reverse input.wav output.wav\n");
        return 1;
    }

    // Open input file for reading
    // TODO #2
    FILE *input = fopen(argv[1], "rb");
    if (input == NULL)
    {
        printf("could not open file\n");
        return 2;
    }

    // Read header into an array
    // TODO #3
    WAVHEADER header;
    fread(&header, HEADER_SIZE, 1, input);

    // Use check_format to ensure WAV format
    // TODO #4

    if (check_format(header) == 5)
    {
        printf("Incorrect file format\n");
        return 3;
    }

    // Open output file for writing
    // TODO #5
    FILE *output = fopen(argv[2], "wb");
    if (output == NULL)
    {
        printf("could not open file\n");
        return 4;
    }

    // Write header to file
    // TODO #6
    fwrite(&header, HEADER_SIZE, 1, output);

    // Use get_block_size to calculate size of block
    // TODO #7
    int block_size = get_block_size(header);
    printf("block size is: %d\n", block_size);

    // Write reversed audio to file
    // TODO #8
    fseek(input, 0, SEEK_END);
    // long here = ftell(input);

    int *Buffer[block_size];
    do
    {
        fread(Buffer, block_size, 1, input);
        fwrite(Buffer, block_size, 1, output);
        fseek(input, -8, SEEK_CUR);
        long here = ftell(input);
        // printf("here is: %ld\n", here);
    }
    while (ftell(input) >= HEADER_SIZE);
    
    fclose(input);
    fclose(output);
}


int check_format(WAVHEADER header)
{
    // TODO #4
    BYTE *format = header.format;

    if (format[0] == 'W' && format[1] == 'A' && format[2] == 'V' && format[3] == 'E')
    {
        printf("is a wave file\n");
        return 0;
    }
    else
    {
        printf("Bad\n");
        return 5;
    }
}
int get_block_size(WAVHEADER header)
{
    // TODO #7
    int block_size = header.numChannels * (header.bitsPerSample / 8);
    return block_size;
}

问题排查与修正

1. 缓冲区类型定义错误

代码中int *Buffer[block_size];定义的是指针数组,并非用来存储音频字节数据的缓冲区。音频块是原始字节流,应该使用BYTE类型的数组:

BYTE Buffer[block_size];

2. fseek偏移量固定值错误

当前代码用fseek(input, -8, SEEK_CUR);固定偏移8字节,这只适用于特定块大小的情况(比如双声道16位采样,块大小是4,8是2倍块大小),但通用情况下应该使用-2 * block_size作为偏移量:

  • 每次读取一个块后,需要回退两个块的位置:一个是刚读取的块,另一个是下一个要读取的块的起始位置。

3. 循环边界逻辑错误

原do-while循环会重复读取最后一个音频块(文件头前的块),且未考虑音频总块数的边界。正确的做法是先计算总块数,再定位到最后一个块的起始位置,循环读取并写入:

// 修正后的反转逻辑
fseek(input, 0, SEEK_END);
long data_size = ftell(input) - HEADER_SIZE;
int total_blocks = data_size / block_size;

// 定位到最后一个音频块的起始位置
fseek(input, HEADER_SIZE + (total_blocks - 1) * block_size, SEEK_SET);

BYTE Buffer[block_size];
for (int i = 0; i < total_blocks; i++)
{
    fread(Buffer, block_size, 1, input);
    fwrite(Buffer, block_size, 1, output);
    // 最后一个块不需要再偏移,避免越界
    if (i != total_blocks - 1) {
        fseek(input, -2 * block_size, SEEK_CUR);
    }
}

4. (可选)check_format返回值优化

虽然不影响功能,但返回值用5不够直观,可以改为返回1表示错误,0表示正确,让逻辑更清晰:

int check_format(WAVHEADER header)
{
    BYTE *format = header.format;
    if (format[0] == 'W' && format[1] == 'A' && format[2] == 'V' && format[3] == 'E')
    {
        printf("is a wave file\n");
        return 0;
    }
    else
    {
        printf("Bad\n");
        return 1;
    }
}
// 对应main中的判断改为
if (check_format(header) != 0)
{
    printf("Incorrect file format\n");
    return 3;
}

内容的提问来源于stack exchange,提问作者Diaplo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 22:21:38