前言

之前程序是32位的,切到64位之后,一些隐藏的问题就暴露了。这不,一个由字节对齐导致的挂死问题就出来了。

字节对齐和64位

关于字节对齐,可参考《理一理字节对齐的那些事》,而之前也分享过另一个切64位之后出现的问题,有兴趣的可以查看《记64位地址截断引发的挂死问题》。

本文背景

本文出现的场景是,系统需要解析JSON文件,但是出现部分功能解析正常,部分挂死,并且32位程序正常,而64位程序挂死。鉴于原系统比较复杂,本文将会简化其过程,来看看到底是什么导致了挂死。
本文示例代码主要引自《一个超轻量级的JSON解析器》。

简化后示例代码

//来源:公众号【编程珠玑】
//https://www.yanbinghu.com
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<string.h>
#pragma pack(1)
#include"cJSON.h"
#pragma pack()/*省略部分代码,完整代码可查看附录部分*/
int main(void)
{char *filename = "./test.json";cJSON *pJson = NULL;cJSON *pTemp = NULL;pJson = prepare_parse_json(filename);if(NULL == pJson){printf("parse json failedn");return -1;}/*获取name值*/pTemp = cJSON_GetObjectItem(pJson,"name");printf("name is %sn",pTemp->valuestring);/*获取site值*/pTemp = cJSON_GetObjectItem(pJson,"site");printf("site is %sn",pTemp->valuestring);/*获取age值*/pTemp = cJSON_GetObjectItem(pJson,"age");printf("age is %dn",pTemp->valueint);/*记得释放相关内存*/cJSON_Delete(pJson);pJson = NULL;return 0;
}

编译运行结果:

$ gcc -L. -o parseJson parseJson.c -lcjson
$ ./parseJson
Segmentation fault (core dumped)

在实际中我们通过GDB观察发现,在解析JSON内部查看JSON数据是完好的,但是调用完解析JSON之后,再去访问使用就不对了,并且我们发现,在不同的功能模块中,调用结果不一样,大部分模块调用并没有任何问题,而只有某个功能模块调用出现问题。

真相

到底是什么导致的呢?
问题的根源在于下面这几行代码:

#pragma pack(1)
#include"cJSON.h"
#pragma pack()

另外补充,cJSON结构体如下:

typedef struct cJSON {  //cJSON结构体struct cJSON*next,*prev;           /*后驱节点和前驱节点*/struct cJSON *child;                   /*孩子节点*/int type;                                     /* 键的类型*/char *valuestring;                       /*字符串值*/int valueint;                                /* 整数值*/double valuedouble;                    /* 浮点数值*/char *string;                               /* 键的名字*/
} cJSON;

#pragma指令说明了按一字节对齐,而cJSON的头文件也在其中,那么就会导致里面的cJSON结构体按照1字节对齐,最终其结构体大小为56个字节而已经编译好的cjson库可并非如此,因此对于64位程序,它还是按照8字节对齐,结构体大小为64字节,而对于32位程序,按照4字节和1字节对齐,都是36字节。

同一个结构体的大小竟然在不同的代码中大小不一样!

最终也就出现了我们遇到的情况,64位程序由于库中申请结构体内存大小与外部调用不一样,最终导致挂死,而32位程序解析JSON正常。

来源:公众号编程珠玑
博客:https://www.yanbinghu.com

总结

幸运的是,本文示例中能够很明显的能看到问题所在,但在实际项目中,如果头文件管理不规范,并且项目的产品多样,通过编译宏来隔开使用的头文件,就很难发现这样的问题。

思考

什么情况下需要1字节对齐呢?

附录

本文完整代码请查看字节对齐不慎引发的挂死问题的附录部分。

微信公众号【编程珠玑】:专注但不限于分享计算机编程基础,Linux,C语言,C++,数据结构与算法,工具,资源等编程相关[原创]技术文章。

对齐方式有那些_字节对齐不慎引发的挂死问题相关推荐

  1. 字节对齐不慎引发的挂死问题

    前言 之前程序是32位的,切到64位之后,一些隐藏的问题就暴露了.这不,一个由字节对齐导致的挂死问题就出来了. 字节对齐和64位 关于字节对齐,可参考<理一理字节对齐的那些事>,而之前也分 ...

  2. java 字节对齐_字节对齐

    字节对齐 为什么字节对齐? 一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存.一个字起始地址是奇数但却没有跨越字边界被认为是对齐 ...

  3. PyQt5 技术篇-设置alignment对齐方式。Qt Designer设置文本对齐方式。居中、左对齐、右对齐、上对齐、下对齐。

    通过 alignment 设置,展开后可以设置水平方向或垂直方向的对齐方式. PyQt5 设置文本对齐方法: self.label.setAlignment(QtCore.Qt.AlignRight| ...

  4. php设置表格字体对齐方式,Excel 表格字体与对齐方式设置

    输入数据后,默认情况下的显示效果是:"常规"格式.11号宋体字.文本左对齐和数字右对齐.而在实际操作中,需要对这些默认的格式进行修改,以满足特定的需要. 设置表格字体 输入数据到单 ...

  5. java字节对齐原则_C struct 中字节对齐问题

    为了提高CPU的存储速度,VC对一些变量的 起始地址做了"对齐"处理.在默认情况下,VC规定各成员变量存放的起始地址相对于结 构的起始地址的偏移量必须为该变量的类型所占用的字节数的 ...

  6. c语言4字节对齐,理一理C语言字节对齐的那些事

    前言 字节对齐是我们初学 C语言 就会接触到的一个概念,但是到底什么是字节对齐?对齐准则又是什么?为什么要字节对齐呢?字节对齐对我们编程有什么启示?本文将简单理一理字节对齐的那些事. 什么是字节对齐 ...

  7. java label对齐方式_java – 在BorderLayout中对齐JLabel和JTextField

    我只是尝试使用一些GUI组件的Java BorderLayout和GridLayout. 我正在尝试右对齐JLabel并左对齐JTextFields,以便它可以更好看. 在setAlignmentX和 ...

  8. 怎么把位域合成一个字节_C语言中字节对齐和位域

    1.1基本类型默认字节对齐和改变字节对齐方式 c语言在给不同类型变量分配地址空间时,并不是总是紧邻着上一个变量的地址空间分配的,而是它所在的地址空间,必须被它的默认对齐字节数整除.例如,int类型占4 ...

  9. linux下字节对齐

    一,内存地址对齐的概念    计算机内存中排列.访问数据的一种方式,包含基本数据对齐和结构体数据对齐.    32位系统中,数据总线宽度为32,每次能够读取4字节数据.地址总线为32,最大寻址空间为4 ...

最新文章

  1. BZOJ4280 : [ONTAK2015]Stumilowy sad
  2. 如何统计不重复姓名的个数?
  3. 跨平台传输中使用base64来保证非ascii码字符串的完整性
  4. 高并发编程-Thread_正确关闭线程的三种方式
  5. 【更新】Individual Homework Agile Development reading
  6. 通过 微软 pai-fs 上传数据到HDFS (Microsoft OpenPAI)
  7. SQL:postgresql增加自增字段
  8. sparksql优化_Spark SQL | 目前Spark社区最活跃的组件之一
  9. 算法:查找序列最小k元素(分治法)
  10. [有限元方法阶段汇总篇] 有限元入门简单 1D 示例程序(Helmholtz 方程)
  11. MOS管的工作原理以及设计理念
  12. 微前端架构实现(项目引入,消息总线,构建部署,监听服务)
  13. 编译器报错The type of the expression must be an array type but it resolved to int.
  14. html,css维护优化,网站CSS代码优化的7个原则
  15. maya2020linux下卸载,卸载产品的步骤 | Maya 2022 | Autodesk Knowledge Network
  16. Python门面设计模式
  17. meego linux 双系统,如何安装MeeGo和Windows 7双系统
  18. linux hub设备,linux usb hub初始化
  19. TFT液晶屏驱动移植
  20. 知乎高赞:假如我有500w存进余额宝,可以每天坐着等吃吗?

热门文章

  1. Policy-based RL小结(Policy Gradient ; Natural policy gradient ;TRPO;ACKTR;PPO )
  2. 强化学习6——policy gradient的变种State of the Art
  3. codeforces div2 C. Ehab and a 2-operation task
  4. python tkinter_Python+tkinter开发一个电子宠物(2 按钮)
  5. javascript设计模式_开发者都应该了解的7种JavaScript设计模式
  6. 判断给定的整数数组是不是某二叉搜索树的后序遍历的结果
  7. python控制语句第一章_【原创】Python第一章
  8. NAND FLASH 和NOR FLASH工作原理
  9. 启明云端分享| sigmastar ssd201_ffmpeg移植
  10. Esp32-CAM(ESP32带camera)使用说明