Fer*_*eak 5 c c++ character-encoding
对于我的宠物项目,我正在尝试字符串表示,但我得到了一些令人不安的结果.首先,这是一个简短的应用程序:
#include <stdio.h>
#include <stddef.h>
#include <string.h>
void write_to_file(FILE* fp, const char* c, size_t len)
{
void* t = (void*)c;
fwrite(&len, sizeof(size_t), 1, fp);
fwrite(t, len, sizeof(char), fp);
}
int main()
{
FILE* fp = fopen("test.cod", "wb+");
const char* ABCDE = "ABCDE";
write_to_file(fp, ABCDE, strlen(ABCDE) );
const char* nor = "BBøæåBB";
write_to_file(fp, nor, strlen(nor));
const char* hun = "AA??éáöüúBB";
write_to_file(fp, hun, strlen(hun));
const char* per = "CC???CC";
write_to_file(fp, per, strlen(per));
fclose(fp);
}
Run Code Online (Sandbox Code Playgroud)
它没有什么特别的,只需要一个字符串,并将它的长度和字符串本身写入文件.现在,该文件在被视为十六进制时看起来像:

我很满意第一个结果,5(前8个字节,我在64位机器上)如预期的那样.但是,nor我期望的变量有7个字符(因为那是我在那里看到的),但是C库认为它有0x0A(即:10个)字符(第二行,0A以及另外8个字符).字符串本身包含双字符(ø编码为C3 B8等等......).
对于hun和per变量也是如此.
我用Unicode做了同样的实验,以下是应用程序:
#include <stdio.h>
#include <stddef.h>
#include <string.h>
void write_to_file(FILE* fp, const wchar_t* c, size_t len)
{
void* t = (void*)c;
fwrite(&len, sizeof(size_t), 1, fp);
fwrite(t, len, sizeof(wchar_t), fp);
}
int main()
{
FILE* fp = fopen("test.cod", "wb+");
const wchar_t* ABCDE = L"ABCDE";
write_to_file(fp, ABCDE, wcslen(ABCDE) );
const wchar_t* nor = L"BBøæåBB";
write_to_file(fp, nor, wcslen(nor));
const wchar_t* hun = L"AA??éáöüúBB";
write_to_file(fp, hun, wcslen(hun));
const wchar_t* per = L"CC???CC";
write_to_file(fp, per, wcslen(per));
fclose(fp);
}
Run Code Online (Sandbox Code Playgroud)
这里的结果是预期的结果.5为长度为ABCDE7的长度BBøæåBB等等,每个字符4个字节...

所以这里有一个问题:标准C库的编码是什么,以及在开发可移植应用程序时它是多么可信(即:我在平台上写的内容将在另一个上正确读回?)以及其他什么建议考虑上面提到的内容.
据我所知,标准C库根本不进行编码.我想在第一种情况下你的输入文件使用UTF-8作为编码,因此你的字符串常量最终将作为编译代码中的UTF-8字符串常量.这就是为什么你得到长度为10个字符的字符串.
fwrite将(无类型)字节数组作为参数.由于它对处理的字节一无所知,因此根本不能进行任何编码转换.
关于可移植性,你应该更加小心指针长度等事情.fwrite(&len, sizeof(size_t), 1, fp)可以在不同平台上产生不同的结果,可能导致您的文件被错误地读取.另外(特别是对于多字节编码)你必须小心平台的字节序.
对于其他任何事情,您可以确定,您的标准库会将字节精确地放入磁盘,但在将它们作为文本处理时,您必须确保在所有平台上使用相同的编码.