百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

C语言结构体对齐和运算顺序优先级的讨论

haoteby 2024-12-20 15:44 4 浏览

第一个问题:结构体对齐

在做一个小型通信系统时,为了方便通信帧解析以及数据存储,通过结构体定义了该数据帧的结构。代码写完之后进行系统调试,一切进展顺利,最后当调试到存储部分时出了问题,通过监视发现通讯帧结构正确但是存储数据始终不正确,经过深入分析发现系统中定义了如下一个结构体HostNode,在存储的时候采用sizeof运算符对HostNode结构体获取长度,按照设计该长度应该为6+2+1=9字节,而实际上sizeof运算符得到的长度为10,这导致了存储错误。

typedef struct

{

my_u8 std_addr[6];

my_u16 short_addr;

my_u8 status;

}HostNode;

追究问题的根本原因在于部分32位MCU设计上为了追求更高的效率默认采用字对齐方式对数据进行运算和处理的,网络上相关讨论已经比较多,这里引用http://jinguo.javaeye.com/blog/361928的记录作为参考。

首先,声明几个概念:

(1)、对象:在C语言中使用结构体类型、共同体类型、或内部基本类型所定义的变量或常量,就称为对象。对象占据了一块实际的存储器空间,这块空间有固定的起始地址和字节数。

(2)、引用:使用对象有两种方法:“对象名”和“引用”。当你在源代码中定义一个对象时,编译器就会为它分配一块存储器,此时,我们就可以使用“对象名”来操作该对象。但是对于程序运行时动态分配的某一块存储器空间(对象),就没法使用“对象名”了,而只能使用“引用”。所以,“引用”就是指向特定类型的对象的指针。

在32位嵌入式系统中,单字节对象是1字节对齐的;双字节对象是2字节对齐的;四字节对象是4字节对齐的;其它结构体或共同体对象是8字节对齐的。也就是说:

(1)在定义一个单字节对象时,该对象的起始地址可以是任何整数;

(2)定义一个双字节对象时,该对象的起始地址必定是2的倍数的整数;

(3)定义一个四字节对象时,该对象的起始地址必定是4的倍数的整数;

(4)定义一个结构体或共同体对象时,该对象的起始地址必定是8的倍数的整数。

以上说的对象包括“结构体或共同体对象的成员对象”。

字节对齐的故障只能出现在“引用”的使用过程中。当使用“对象名”来操作对象时,根本不用担心字节对齐问题。

在ADS环境下,有“ALIGN” 、“__align(x)” 、“__packed”关键字用于字节对齐处理。ALIGN用于汇编语言,__align(x)用于C语言,__packed用于放弃字节对齐。

单字节对齐类型的引用可以操作任何对象,双字节对齐类型的引用可以操作双字节、四字节、八字节对齐的对象。只有遵守这个规则,程序才可能是健壮的。

如果我们想使用双字节对齐类型的引用来操作单字节对齐对象,那么你在定义该引用时必须使用__packed关键字


第二个问题:C语言的运算优先顺序

在原通信系统设计中使用了如下一句代码

if((end_dev_bit_map[i]<<j)&0x80 != 0x80)

{

}else

{

}

结果为调试带来了很大的麻烦。本来条件表达式想表明如果end_dev_bit_map[i]从左向右的第j位如果不为1,而事实上因为表达式(end_dev_bit_map[i]<<j)&0x80 != 0x8是按照从左到右进行运算的,而!=和&处于同一个运算级别,就导致了先计算0x80!=0x80,该结果为0,然后再与之前的表达式进行&运算,恒等于零,导致整个条件表达式恒为假,从而引起程序错误。

总结

1.32位系统中定义结构体必须谨慎,尤其是存在强制类型转换的代码,需要考虑结构体中的字对齐产生的“空隙”。

2,经过keil对stm32f101设备的仿真发现,采用__packet紧缩型定义的结构体读写操作并没有浪费时间,因此非对齐型结构体定义对速度的影响因设备而异。

3.在C代码编写时最好多加括号以保证运算按照自己设计的先后顺序进行(尽管这样做会使代码比较难看),这样做的好处是代码移植性好,没有风险。

相关推荐

单点登录(SSO)解决方案介绍(单点登录概念)

一、单点登录的介绍单点登录(SingleSignOn),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系...

系统登录的三种方式,哪一种更安全?

登录是一个高频的动作,笔者抓住这一个小点,分析了系统登录的几种方式和对应的场景。今天谈谈登录。登录即用户输入用户名和密码登录进系统中。B端系统,对于登录的业务场景有两种(可能不止,目前遇到过这两种):...

到底什么是单点登录(SSO)?(什么叫做单点登录)

什么是单点登录?单点登录(SingleSign-On,简称SSO)是一种集中式的身份验证和授权机制,用户只需在一处输入一次凭证(例如用户名和密码)就可以访问多个相关但独立的软件系统。在数字化时代,...

5年稳如老狗的单点登录系统,到底是怎么搞出来的?

说到单点登录(SingleSign-On,简称SSO),大家的第一反应可能是——啊不就是登录一次,能到处串门儿嘛?别说,还真差不多,就是这么个意思。但真要搭一套好用、耐造、还能扛住公司里各种奇奇怪...

这些负载均衡都解决哪些问题?服务、网关、NGINX?

在微服务项目中,有服务的负载均衡、网关的负载均衡、Nginx的负载均衡,这几个负载均衡分别用来解决什么问题呢?一、服务的负载均衡先抛出一个问题:...

Nginx负载均衡最全详解(4大算法原理机制)

Nginx在大型网站架构很重要,也是大厂重点考察方向,今天我就重点来详解Nginx负载均衡@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》里面。Nginx负载均衡N...

负载均衡 Nginx Session 一致性(nginx 负载均衡 会话保持)

HTTPS请求跳转...

监控Oracle Cloud负载均衡器:Applications Manager释放最佳性能

设想你正在运营一个受欢迎的在线学习平台,在考试前的高峰期,平台流量激增。全球的学生同时登录,观看视频、提交作业和参加测试。如果OracleCloud负载均衡器不能高效地分配流量,或者后端服务器难...

Nginx负载均衡:nginx.conf配置文件说明!

大家好,欢迎来到程序视点!我是你们的老朋友.小二!在此记录下Nginx服务器nginx.conf负载均衡的配置文件说明,部分注释收集与网络.关于nginx.conf基本的配置,请查看上一篇文章!Ng...

Java高可用系统架构中的负载均衡策略

Java高可用系统架构中的负载均衡策略在现代的分布式系统中,负载均衡策略是构建高可用系统的基石。Java开发者需要深刻理解这些策略,以便打造稳定且高效的系统。接下来,让我们一起揭开负载均衡的神秘面纱。...

深入对比Nginx、LVS和HAProxy,选择最合适负载均衡方案!

关注...

Spring Boot3 客户端负载均衡全解析:从原理到实战

在当今互联网大厂后端技术开发的激烈竞争环境中,构建高效、稳定的微服务架构是核心诉求。其中,SpringBoot3作为热门开发框架,其客户端负载均衡功能对于提升系统性能、保障服务稳定性起着关键作用。...

MySql高可用集群MySQL Router负载均衡读写分离

名词解释MGR:MysqlGroupReplication组复制,多台MySQL服务器在同一组中会自动保持同步状态,当某台服务器故障时,整个复制组依然可以保持正常并对外提供服务。...

性能测试之tomcat+nginx负载均衡(nginx tomcat)

nginxtomcat配置准备工作:两个tomcat执行命令cp-rapache-tomcat-8.5.56apache-tomcat-8.5.56_2修改被复制的tomcat2下con...

win10/11双网卡链路聚合叠加负载均衡提升网速解决网卡网速瓶颈!

双网卡链路聚合一种网络配置技术,通过将多个物理网卡绑定在一起,形成一个逻辑上的网络接口,以提高网络的可靠性、可用性和性能。这种技术通常用于服务器和网络设备中,以实现负载均衡、冗余和高可用性。本机环境:...