跨平台 UTF-8 字符文件数据 encoding/decoding
Cross platform UTF-8 char file data encoding/decoding
我使用数据结构对二进制文件进行编码,其中 属性 之一是 wchar_t 类型以支持 UTF-8。
每个结构如下所示:
struct DataBlock{
wchar_t charcode;
int width;
int height;
///etc
}
编码发生在 Windows,其中 wchar_t 大小为 2 个字节。
文件解码发生在Linux,大小为 4 bytes.So Linux 侧的 charcode 读出值错误。
在不对 UTF 使用 3rd party libs 的情况下解决该差异的最佳方法是什么?是否可以编码字符码,例如在 win 上编码为 'int' 数据类型,然后在 [=29 上编码为 'int' 数据类型=] 投射到 wchar_t?
unicode 完整字符集当前需要 32 位来表示所有可能的值:
- UTF-32 编码将这些字符存储在 4 个字节中,也就是一个
uint32_t
。
- UTF-16编码将每个unicode字符存储成一两个
uint16_t
- UTF-8编码将每个unicode字符存储为一到四个
uint8_t
通常,windows uses wchar_t
to store unicode text in UTF-16 encoding. At the time this was decided, UTF-16 was able to hold all the unicode caracter set, which is no longer true today。 Linux 使用 UTF-8 编码。大多数实现使用 char
以 UTF-8 格式存储 unicode 文本。
该标准为您提供了一些工具来应对编码转换:
当reading/writing流时,您可以使用wbuffer_convert
together with codecvt
面在wchar_t
UTF16和UTF8编码之间转换。
您还可以使用wstring_convert
在UTF16和UTF8之间转换已经加载到内存中的字符串。
如果你只想在二进制文件中使用跨系统数据结构而不进行转换,只需使用:
struct DataBlock{
uint16_t charcode; // if you assing in windows from a wchar_t, no problem
...
}
编写二进制结构本质上是不可移植的。坏事几乎无处不在:
- 对于任何大于
char
的类型,您都可能遇到字节顺序问题
- 对于任何小于 8 字节的类型,您都可能会遇到对齐问题 - 即使可以在支持它的体系结构和编译器上使用
#pragma
来缓解这种问题。
您应该避免这种情况,而是使用一种 marshalling,即以明确且独立于体系结构的方式进行序列化。例如:
wchar_t charcode
- 假设你的 charcode 永远不会使用超过 2 个字节,你明确地将它转换为 char[2]
(实际上我强制使用 2 个字节大字节序表示):
code[0] = (charcode >> 8) & 0xFF;
code[1] = charcode & 0xFF;
int
- 你知道你是否需要2、4或8个字节来表示width
和[=的任何值21=];假设它是 4 (int32_t
或 uint32_t
)
code[0] = (width >> 24) & 0xFF;
code[1] = (width >> 16) & 0xFF;
code[2] = (width >> 8) & 0xFF;
code[3] = width & 0xFF;
因此,您在具有确定大小的 char
数组中明确定义 struct DataBlock
的转换。现在您确实拥有了可移植到任何网络、体系结构或编译器上的东西。当然,您已经明确地编写了用于编码和解码的 2 例程,但这是我所知道的拥有 可移植二进制结构 .
的唯一方法
希望htonx
功能可以帮到您。它们明确采用 16 位或 32 位整数,并强制按 network(大端)顺序进行转换。来自 Linux 手册页:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
htonl() 函数将无符号整数 hostlong 从主机字节顺序转换为网络字节顺序。
htons()函数将无符号短整数hostshort从主机字节序转换为网络字节序。
ntohl() 函数将无符号整数 netlong 从网络字节顺序转换为主机字节顺序。
ntohs() 函数将无符号短整数 netshort 从网络字节顺序转换为主机字节顺序。
这样,您就可以直接编写结构的字段:
long l = htonl(data.charcode); // or htons if you only need 16 bits
fwrite(&l, sizeof(long), 1, fdout); // sizeof(short) if you used 16 bits
阅读也一样:
long l;
fread(&l, sizeof(long), 1, fdin);
data.charcode = ntohl(l);
这个函数已经在类 Unix 系统下定义了很长时间,并且似乎在最近版本的 Windows 编译器上定义。
当然,如果你绝对确定你只会使用小端架构,你甚至可以不转换为字节序。但请务必在您的文档中更正,最好使用红色闪烁字体...
我使用数据结构对二进制文件进行编码,其中 属性 之一是 wchar_t 类型以支持 UTF-8。
每个结构如下所示:
struct DataBlock{
wchar_t charcode;
int width;
int height;
///etc
}
编码发生在 Windows,其中 wchar_t 大小为 2 个字节。
文件解码发生在Linux,大小为 4 bytes.So Linux 侧的 charcode 读出值错误。
在不对 UTF 使用 3rd party libs 的情况下解决该差异的最佳方法是什么?是否可以编码字符码,例如在 win 上编码为 'int' 数据类型,然后在 [=29 上编码为 'int' 数据类型=] 投射到 wchar_t?
unicode 完整字符集当前需要 32 位来表示所有可能的值:
- UTF-32 编码将这些字符存储在 4 个字节中,也就是一个
uint32_t
。 - UTF-16编码将每个unicode字符存储成一两个
uint16_t
- UTF-8编码将每个unicode字符存储为一到四个
uint8_t
通常,windows uses wchar_t
to store unicode text in UTF-16 encoding. At the time this was decided, UTF-16 was able to hold all the unicode caracter set, which is no longer true today。 Linux 使用 UTF-8 编码。大多数实现使用 char
以 UTF-8 格式存储 unicode 文本。
该标准为您提供了一些工具来应对编码转换:
当reading/writing流时,您可以使用
wbuffer_convert
together withcodecvt
面在wchar_t
UTF16和UTF8编码之间转换。您还可以使用
wstring_convert
在UTF16和UTF8之间转换已经加载到内存中的字符串。
如果你只想在二进制文件中使用跨系统数据结构而不进行转换,只需使用:
struct DataBlock{
uint16_t charcode; // if you assing in windows from a wchar_t, no problem
...
}
编写二进制结构本质上是不可移植的。坏事几乎无处不在:
- 对于任何大于
char
的类型,您都可能遇到字节顺序问题 - 对于任何小于 8 字节的类型,您都可能会遇到对齐问题 - 即使可以在支持它的体系结构和编译器上使用
#pragma
来缓解这种问题。
您应该避免这种情况,而是使用一种 marshalling,即以明确且独立于体系结构的方式进行序列化。例如:
wchar_t charcode
- 假设你的 charcode 永远不会使用超过 2 个字节,你明确地将它转换为char[2]
(实际上我强制使用 2 个字节大字节序表示):code[0] = (charcode >> 8) & 0xFF; code[1] = charcode & 0xFF;
int
- 你知道你是否需要2、4或8个字节来表示width
和[=的任何值21=];假设它是 4 (int32_t
或uint32_t
)code[0] = (width >> 24) & 0xFF; code[1] = (width >> 16) & 0xFF; code[2] = (width >> 8) & 0xFF; code[3] = width & 0xFF;
因此,您在具有确定大小的 char
数组中明确定义 struct DataBlock
的转换。现在您确实拥有了可移植到任何网络、体系结构或编译器上的东西。当然,您已经明确地编写了用于编码和解码的 2 例程,但这是我所知道的拥有 可移植二进制结构 .
希望htonx
功能可以帮到您。它们明确采用 16 位或 32 位整数,并强制按 network(大端)顺序进行转换。来自 Linux 手册页:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
htonl() 函数将无符号整数 hostlong 从主机字节顺序转换为网络字节顺序。
htons()函数将无符号短整数hostshort从主机字节序转换为网络字节序。
ntohl() 函数将无符号整数 netlong 从网络字节顺序转换为主机字节顺序。
ntohs() 函数将无符号短整数 netshort 从网络字节顺序转换为主机字节顺序。
这样,您就可以直接编写结构的字段:
long l = htonl(data.charcode); // or htons if you only need 16 bits
fwrite(&l, sizeof(long), 1, fdout); // sizeof(short) if you used 16 bits
阅读也一样:
long l;
fread(&l, sizeof(long), 1, fdin);
data.charcode = ntohl(l);
这个函数已经在类 Unix 系统下定义了很长时间,并且似乎在最近版本的 Windows 编译器上定义。
当然,如果你绝对确定你只会使用小端架构,你甚至可以不转换为字节序。但请务必在您的文档中更正,最好使用红色闪烁字体...