引言 - 一种更好的方式
其实不管什么语言, 开发框架都会遇到序列化问题. 序列化可以理解为A 和 B 交互的一种协议.
很久以前利用 printf 和 scanf 的协议实现过一套序列化问题.
C基础 数据序列化简单使用和讨论
本文在上面基础上运用一种新的尝试. 具体的思路是 利用编译器对结构的统一内存编码方式.
具体实现通过进出栈宏 #pragma pack(push, 1) ... #pragma pack(pop) 设置结构体编译器的编码方式.
#pragma pack(push, 1)
struct person {
int id;
char sex;
int age;
char name[65];
double high;
double weight;
};
#pragma pack(pop)
当编译器解析 struct person 的时候, 采用1字节对齐. 保证结构体编解析后二进制数据是一样的(VS 和 GCC测试过).
这是不同系统间通信的不变量之一. 通过这种序列化的思路. 不妨设计一个验证的Demo如下
window 生产者代码
// 设置数据, 开始写到测试文件中,再去读取
struct person per = {
1, 1, 19, "simplec王志", 179.0, 70.1
};
// 这里开始写数据到文件中.
const char * path = "person.txt";
FILE * txt = fopen(path, "wb");
if (NULL == txt)
exit(EXIT_FAILURE);
fwrite(&per, sizeof(struct person), 1, txt);
fclose(txt);
linux 使用者代码
const char * path = "person.txt";
FILE * txt = fopen(path, "rb");
if (NULL == txt)
exit(EXIT_FAILURE);
struct person np;
fread(&np, sizeof(struct person), 1, txt);
printf("[%d, %d, %d, %s, %lf, %lf]\n",
np.id, np.sex, np.age, np.name, np.high, np.weight);
fclose(txt);
实际运行的结果展示.
不知道你是否感到好奇, 为啥最终结果不对呢. 这就扯出了, 编程开发中所有老鸟都必须要面对的坑. "编码统一的坑".
为了将问题表述的更明白, 再来个Demo. sizeofname.c
#include <stdio.h>
#include <wchar.h>
int main(int argc, char * argv[]) {
// 系统默认编码, 一共 2 + 3 + 7 + 1 = 13 个 字符
char as[] = "王志 - simplec";
// 采用宽字节, 2字节表示一个字符
wchar_t bs[] = L"王志 - simplec";
// 采用UTF-8编码, 重要 ☆
char cs[] = u8"王志 - simplec";
printf("sizeof as = %zu.\n", sizeof as);
printf("sizeof bs = %zu.\n", sizeof bs);
printf("sizeof cs = %zu.\n", sizeof cs);
return 0;
}
在window 上运行结果如下, 我的系统默认是gbk编码(ascii码扩充版). 如果装英文版window默认是utf-8.
中间扯个淡. 我的VS设置中默认是 unix utf-8 有 BOM 文件编码格式. 详细配置可以参照这篇博客 - Visual Studio 默认保存为UTF8编码
在linux上测试结果如下, linux默认UTF-8编码
通过上面你也可以看出来, 主要问题是编码不一致导致了乱码. 最终使fread解析出错. 那么随后就开始解决这个问题.
前言总结
1. #pragma pack(push, 1) ... #pragma pack(pop) 是一种 C/C++ 系统间直接序列化的一种高效手段
2. 系统编码推荐统一采用 UTF-8. linux 默认就是, window 中文版是gbk.
下面将提出一种编码统一的方案. 到这里基本可以了, 后面可以选看. O(∩_∩)O哈哈~
前言 - 需要一些帮助,刚好我已经做了
以前有个GNU 的 libiconv 跨平台的库可以解决不同平台的编码问题. 其最近版本对window不再提供直接支持了.
这里我将其继续拉取到window上了搞了一通,最终生成libiconv.lib. 具体可以看下面项目
libiconv-for-window https://github.com/wangzhione/libiconv-for-window
工程详细的配置步骤如下
========================================================================
静态库:libiconv for window 项目概述
========================================================================
/////////////////////////////////////////////////////////////////////////////
当前移植项目基于 GNU 项目 libiconv-1.15 | http://www.gnu.org/software/libiconv/
移植到平台 window 10 14393.953 | Visual Studio 2017
项目发起人 : simplec - wz | wangzhione@163.com
/////////////////////////////////////////////////////////////////////////////
具体操作思路:
1. 从官网下载资源 libiconv压缩包, 并解压 [xxx = 解压后的详细path]
2. 在 $(ProjectDir) 项目目录下, 新建 include 目录
2.1 将压缩包中 xxx/include/iconv.h.build.in 复制到 include 目录下, 并重名为 iconv.h
2.2 将 xxx/onfig.h.in 复制到 include 下, 名为 config.h
2.3 将 xxx/lib 下 所有 *.h and *.def 文件复制到 include 目录下
2.4 将 xxx/libcharset/include/localcharset.h.build.in 复制到 include 目录下, 并改名
3. 将 xxx/libcharset/lib/localcharse