【VS2017】cpp文件字符编码异常导致编译报错
这是一个 wav 转 pcm 的简单demo,但VS2017编译报错
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <inttypes.h>
#pragma pack(push, 1)
struct TWavHead
{int8_t riff[4]; /*!< (4)资源交换文件标志 RIFF */uint32_t file_size; /*!< (4)文件总长度*/int8_t wave[4]; /*!< (4)wav文件标志 WAVE */int8_t fmt[4]; /*!< (4)波形格式标志 FMT */uint32_t fmt_size; /*!< (4)过滤字节 一般为 0x00000010H */uint16_t aud_fmt; /*!< (2)格式种类, 为1时,表示数据为线性PCM编码 */uint16_t channels; /*!< (2)声道数 */uint32_t sample_rate; /*!< (4)采样率 */uint32_t byte_rate; /*!< (4)波形数据传输速率,每秒平均字节数 */uint16_t block_align; /*!< (2)数据调整数,按字节算 */uint16_t bits_pre_sample; /*!< (2)样本位宽(位深) */
};
struct TWavInfo
{int8_t data_flag[4]; /*!< (4)数据标识符 data */uint32_t date_size; /*!< (4)数据长度 */
};
#pragma pack(pop)int main(int argc, char const *argv[])
{if (argc < 2){fprintf(stdout, "no input file\n");return -1;}const char* pchSrcName = argv[1];char achDstName[128] = {0};snprintf(achDstName, 128, "%s.pcm", pchSrcName);FILE* ptSrcFile = fopen(pchSrcName, "rb");FILE* ptDstFile = fopen(achDstName, "wb");TWavHead tHead;TWavInfo tInfo;fread(&tHead, 1, sizeof(TWavHead), ptSrcFile);fseek(ptSrcFile, 2, SEEK_CUR);fread(&tInfo, 1, sizeof(TWavInfo), ptSrcFile);fprintf(stdout, " riff:%c%c%c%c\n", tHead.riff[0], tHead.riff[1], tHead.riff[2], tHead.riff[3]);fprintf(stdout, " file_size:%u\n", tHead.file_size);fprintf(stdout, " wave:%c%c%c%c\n", tHead.wave[0], tHead.wave[1], tHead.wave[2], tHead.wave[3]);fprintf(stdout, " fmt:%c%c%c%c\n", tHead.fmt[0], tHead.fmt[1], tHead.fmt[2], tHead.fmt[3]);fprintf(stdout, " fmt_size:%u\n", tHead.fmt_size);fprintf(stdout, " aud_fmt:%u\n", tHead.aud_fmt);fprintf(stdout, " channels:%u\n", tHead.channels);fprintf(stdout, " sample_rate:%u\n", tHead.sample_rate);fprintf(stdout, " byte_rate:%u\n", tHead.byte_rate);fprintf(stdout, " block_align:%u\n", tHead.block_align);fprintf(stdout, "bits_pre_sample:%u\n", tHead.bits_pre_sample);fprintf(stdout, " data_flag:%c%c%c%c\n", tInfo.data_flag[0], tInfo.data_flag[1], tInfo.data_flag[2], tInfo.data_flag[3]);fprintf(stdout, " date_size:%u\n", tInfo.date_size);uint32_t dwBitNum = tHead.block_align;uint8_t abyBit[128];uint32_t dwRdLen = 0;uint32_t dwSum = 0;for (;;){dwRdLen = fread(&abyBit, 1, dwBitNum, ptSrcFile);if (dwRdLen != dwBitNum){break;}fwrite(&abyBit, 1, dwBitNum, ptDstFile);dwSum += dwBitNum;if (dwSum >= tInfo.date_size){break;}}fflush(ptDstFile);fclose(ptDstFile);fclose(ptSrcFile);fprintf(stdout, "trans over:%u\n", dwSum);return 0;
}
VS2017编译报错:
1>------ 已启动生成: 项目: demo, 配置: Release Win32 ------
1>main.cpp
1>f:\demo\demo\main.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
1>f:\demo\demo\main.cpp(45): error C2039: “wave”: 不是“TWavHead”的成员
1>f:\demo\demo\main.cpp(5): note: 参见“TWavHead”的声明
1>f:\demo\demo\main.cpp(45): warning C4473: “fprintf”: 没有为格式字符串传递足够的参数
1>f:\demo\demo\main.cpp(45): note: 占位符和其参数预计 4 可变参数,但提供的却是 0 参数
1>f:\demo\demo\main.cpp(45): note: 缺失的可变参数 1 为格式字符串“%c”所需
1>已完成生成项目“demo.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
根据您提供的代码和编译错误信息,以下是问题分析及解决方案:
1. 字符编码问题
错误信息:
warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
原因分析:
- 您的源代码文件中包含了中文注释(如
/*!< (4)资源交换文件标志 RIFF */
),而编译器当前使用的代码页(936,简体中文GBK)无法正确表示这些字符。 - 这可能导致编译器在解析字符串字面量时出现问题,尤其是像
int8_t riff[4];
这样的数组初始化,如果其中的字符超出了当前代码页的范围,可能会引发错误。
解决方案:
-
保存文件为 UTF-8 编码:
- 使用支持选择编码的编辑器(如 Visual Studio、Notepad++ 等)打开您的
.cpp
文件。 - 将文件编码更改为 UTF-8(无 BOM)。
- 保存文件后重新编译。
- 使用支持选择编码的编辑器(如 Visual Studio、Notepad++ 等)打开您的
-
或者,确保所有非ASCII字符都在当前代码页内:
- 如果必须使用代码页936,确保所有注释和字符串字面量中的字符都在该代码页的支持范围内。
- 但这种方法较为复杂,推荐使用UTF-8编码。
2. 结构体成员访问错误
错误信息:
error C2039: “wave”: 不是“TWavHead”的成员
note: 参见“TWavHead”的声明
原因分析:
- 由于字符编码问题,编译器可能误解析了结构体
TWavHead
中的成员,导致wave
成员未被正确识别。 - 另外,检查结构体定义是否正确,确保没有拼写错误或遗漏。
解决方案:
-
解决字符编码问题后,重新检查结构体定义:
- 确保
struct TWavHead
中确实定义了int8_t wave[4];
。 - 确认没有拼写错误,例如是否写成了
wav
或其他类似名称。
- 确保
-
示例检查:
struct TWavHead {int8_t riff[4]; /*!< 资源交换文件标志 RIFF */uint32_t file_size; /*!< 文件总长度 */int8_t wave[4]; /*!< wav文件标志 WAVE */int8_t fmt[4]; /*!< 波形格式标志 FMT */// 其他成员... };
3. fprintf
参数不匹配警告
警告信息:
warning C4473: “fprintf”: 没有为格式字符串传递足够的参数
note: 占位符和其参数预计 4 可变参数,但提供的却是 0 参数
原因分析:
- 由于前面的结构体解析错误,编译器可能误认为
tHead.wave
不存在或类型不正确,导致传递给fprintf
的参数数量不足。 - 例如,如果
tHead.wave
被错误地解析为一个单一的int8_t
而不是int8_t[4]
,则%c%c%c%c
需要四个参数,但实际上只传递了一个。
解决方案:
- 首先解决字符编码和结构体成员识别问题。
- 确保
tHead.wave
是一个包含4个元素的数组:- 在结构体定义中,
int8_t wave[4];
应该正确解析为一个长度为4的数组。 - 如果编译器仍然报错,可以尝试显式传递数组元素:
fprintf(stdout, " wave:%c%c%c%c
- 在结构体定义中,
",
tHead.wave[0], tHead.wave[1], tHead.wave[2], tHead.wave[3]);
```
4. 其他建议
-
检查文件路径和权限:
- 确保输入文件存在且程序有读取权限。
- 确保输出文件路径正确且有写入权限。
-
调试编译错误:
- 逐步注释掉部分代码,确认具体是哪一部分引发错误。
- 使用编译器提供的详细错误信息,定位问题源头。
总结
主要问题源于源代码文件的字符编码与编译器的代码页不匹配,导致结构体成员无法正确识别。通过将文件保存为 UTF-8 编码,并确保结构体定义正确,可以解决大部分编译错误。同时,注意 fprintf
的参数传递,确保格式字符串与提供的参数数量一致。
解决
修改demo的cpp文件的字符编码方式,由 UTF-8 修改成 GB2312 后,编译成功!
字符编码修改为 GB2312 后编译成功!