发动态
综合 最新发布 最新回复
图文
列表
拆解预告——天猫精灵
看看天猫精灵用了什么方案!
嘉立创PCB
前些天跟大家解释了如下代码:offset = len/64 + !!(len%64); 并且跟大家详细聊了一下其中的!!操作,然而这段代码的主要功能还是为了进行分包处理,既然是分包自然而然就会想到一种常用的分包处理方法,这也是本文的重点。数据分包在嵌入式软件开发中算是一种非常常见的处理,其主要原因还是硬件上的各种限制,不得已而为之,特别是在通信协议的定制过程中尤为常见。1、传输限制 玩过各种通信协议的朋友都知道,像非常多的通信方式都是以数据帧的形式来进行传递,不同的通信方式因各方面的因素又存在一个最大传输字节数的限制,考虑到稳定性、容错性等等对单次发送的数据长度进行限制,又或者所接收的设备其内存资源有限,不足以接收、处理过长的数据包。像zigbee这样的物理层每帧最大只能传输127个字节,通过每层不断的封包到应用层后每包才100个字节。当上层用户协议的数据包过大,无法一次性传输,就只能分包或者分组下发,最终接收方组包后解析提取数据。2、分包设计的考虑 有些朋友该说了,我就不喜欢搞大包发送,使用短包,然后通过不同的标识进行不同数据位的定义,简单很多。当然长包与短包并没有本质上的区别,其目的都是传输数据,但在实践的过程中还是会遇到居多处理上的区别:数据的同步性方面:比如当通信的设备转速超了,同时报了一个故障码,如果采用短包上传,很可能故障码和转速位于不同的数据包中,当数据包丢包或许是乱序,就会导致当接收到故障码的时候,此时超标的转速值已经丢失或者延时等,有概率不能准确获得故障时的超标转速。而使用长包,只需要发送方能够保证打包的时候同步,那么接收方就可以同步获得相应的数据。通信协议设计自由度方面:在设计协议的时候,长包会更加的自由,大多数情况都不需要考虑大数据传输的占位问题,甚至在编码上直接copy结构体发送也是相当方便的。3、计算包数问题既然长包的设计相对比较方便。那分包处理是少不了的?分包还不简单?要发100个字节的数据,每次只能发15个,那发送7包就可以了,直接编码,代码如下:SendPack = SendNum / PackNum; if(SendPack % PackNum)SendPack++; 这算是常规操作,如果觉得有点难度,还要多敲敲代码。一般用C语言比较久的朋友都想去简化这种操作,毕竟实现一个简单的功能需要两行代码,强迫症,忍不了~就有了本文开头的!!处理方式,或者如下处理也是一样的:#include<stdio.h>#define PackNum(total,single)  (total/single + ((total%single)?1:0)) int main(void) {     printf("packNum: %d\r\n",PackNum(100,15));     printf("packNum: %d\r\n",PackNum(150,15));     printf("packNum: %d\r\n",PackNum(200,15));     printf("packNum: %d\r\n",PackNum(5,15));     printf("hello bug ~\r\n");     return 0; } 仅仅只是秀了一下C语言的几个小技巧罢了,并没有实质性的改善。很明显,本文的重点并不是介绍如上两种办法,而是如下更加高效的代码:PackNum = (total + (singleNum - 1))/singleNum ; 对于一些以往没有使用的朋友或许有点懵,那bug菌这是唠叨几句:该表达式主要是利用了取整的特性来达到+1的目的。直接除单包个数,不能整除的情况,结果都会少1,比如10/6,应该是2包,而由于最终除法结果只能是1。所以通过补偿(singleNum - 1)后,结果就分两种情况:1、原本能够整除的数,补偿后无法整除,结果与之前一致;2、原本不能够整除的数,其余数必然在【1~(singleNum - 1)】之间,所以补偿以后,其余数范围在【singleNum ~(singleNum + singleNum - 2)】,则其结果为整除部分+1。与我们分包个数是一致的,相当巧妙。4、扩展这种方法不仅仅只是用于通信的分组中,把思维进一步泛化。只要是类似分组的处理都可以使用该算法。比如内存的分区,flash的设计上都是一个扇区一个扇区的分布。现在想分配整数个扇形区域用于存储某些数据,每一个扇区512个字节,存储2000个字节的数据,该分配几个扇区?我相信你已经有答案了~
谈谈数据分包以及相关小技巧
嘉立创PCB
引出AD信号后,问题修护了,是软件问题还是硬件问题?
最近升级了一款产品,与其说是升级,更多的还是降本和替代。 降本就不用多说了,每次产品升级都是考虑的重要指标,能省则省,甚至不放过一颗电容、一个电阻,一个字"抠"。 而替代也是近段时间的主题,很多芯片可以说基本买不到,即使买得到也是从40元到了400元,10倍的价格还不能保证交期,还能不能好好玩耍?更可怕的是同样的芯片一个供应商一个价,也不知道是真买不到还是假买不到。 既然这么多事情,又加上人手紧张,只能亲自操刀,当然也是轻车熟路。调试完设备就把固件给硬件和测试去做可靠性了,硬件组装了5台机器,其中有一台机器上位机采样数据死活偏差了100mv。 这部分采样采用多路复用,发现问题以后就一台机器有问题,那只能硬件先上去排查,硬件的小兄弟也是各种测试对比,从输入到AD口一级一级排查,晚上7、8点跟我讨论说,实在是找不到问题了,一起讨论一下还能有什么办法定位原因, 我问他信号有没有确认过,他说从输入到输出都测量过了,信号都是没有问题的。当时我就想不可能呀,这AD采样原始值就显示有所偏差,驱动部分也是应用在蛮多款产品上了。 好吧,那就一起看看吧~ 他跟我展示了一下自己的一些确认结果,通过不同机器对比运放输出信号都是没问题,难道从多路复选芯片到ADC引脚存在问题? 而ADC引脚是多路信号的不同时刻的选通,直接测量有点难分辨,此时我要他把其他信号都拉3.3V,那么此时ADC引脚的低电平必然就是所想要的信号了。按照这样的方法,引出了一些信号点到示波器上,所采集的问题信号确实与正常信号是一致的。 奇怪了,怎么会有问题呢?百思不得其解~ 然而当我再次瞄了一下上位机上的采样数据,正常了~ 难道是因为接了示波器探头的缘故?还原现场! 拆掉看看什么情况? 重新上电看看什么情况? 看来是不出现了,真的是玄学~ 会不会是因为虚焊?或者有锡渣?....... 硬件的小兄弟,一脸蒙圈,说不可能的,今天因为这个问题还重新焊接过。
嘉立创PCB
今天终于安安静静的坐下来分享一些东西,根据今年的一些规划和目标,应该是非常忙的一年,再加上疫情的反复、各大厂的裁员、还有目前国际大环境等等都多多少少影响着我们的生活,跟一些同事和朋友的交流当中我也隐隐约约感受到大家的一丝焦虑和担忧。其实大可不必这样,一味担心一些未知东西或许仅仅只是一种自耗吧,还是要调整好心态。好了,今天谈论的话题是C语言中为何没法规避全局变量?为什么突然谈论这个话题,主要是最近有几个粉丝朋友问到了类似的问题。"bug菌,我代码中全局变量太多了,有没有一种方法不使用全局变量来编写C语言程序?"等等当时并没有感觉特别惊讶,因为曾经的我也是在这条道路上探索着,只是在C语言编程这条路上走得多一点,相对想得更加明白一点罢了。我的回答是:"没有办法规避全局变量的~"1、耦合其实自认为"没有办法规避全局变量的",这个答案相对而言并不是特别专业,却能够让更多的人听懂。在最开始使用C语言进行项目开发的过程中,都会提示要你用模块化思想来编程,怀着"低耦合,高内聚"的编程理念。但是你应该没有听说过模块之间无耦合吧,所以耦合和内聚都是相对而言,当采用了一种不是最优的设计思想和方法,便编写出了一套耦合度较高的代码罢了。而所谓的耦合便是你所划分的各功能模块代码之间的数据共享了。bug菌一直相信代码中的所有设计都可以在这世间找到类比原型,同样这世间规律也完全可以用程序来进行表达,只是目前的科技水平还并没有达到那么水平,或许人工智能就是一个萌芽吧。而在C语言中全局变量的使用,便是一种数据共享的方式,同样也是模块化沟通的桥梁。有朋友该说了,我不进行数据共享便不会使用全局变量了。比如点了个灯,同时又写了串口通信程序,两者并没有什么联系,各自安好,那确实没有数据共享,也可以不使用全局变量,最多认为你在静态存储区定义了几个变量吧。但这样的程序又能复杂到什么程度,或实现什么功能呢?基本没有特别大的意义。2、联系这世间原本就是千丝万缕羁绊着而存在,或许从蝴蝶效应看来就会颇有感触,那么编程中也是一样的,相互之间的存在着某种联系才愈发精彩,而这种联系的表达则少不了数据的共享。程序员们要用C语言来描述这世间种种规律,使用全局变量还逃得掉吗?即便有一种语言可以达到不使用类似于全局变量的语法形式,但数据的共享终究逃不了。虽话说回来,无法规避,但并非没有章法;不加约束,必将带来不少麻烦。3、面向对象面向对象的程序设计思想就是目前约束全局变量使用的一味良药,面向对象与面向过程都是一种思维方式的存在,并非孰优孰劣。但就目前软件设计的发展来看,面向对象的程序设计思想在大型程序的设计和把控上有更多的优势。它能够把各个抽象的个体描绘得更加的直观,这样个体之间的相互联系也就顺理成章的表达和约束。
C语言如何规避全局变量?不可能~
嘉立创PCB
在学校或者各种编程类书本上,基本上都会看到一句话:"函数是程序的基本组成单位",可以说理解函数对编程是非常重要的,与函数调用紧密结合的机制就是函数调用栈了,而栈有一个特别的属性就是栈的增长方向问题了,也发现一些多年编程经验的朋友对这一块都有点迷迷糊糊的。在阅读RTOS源码的时候也会经常看到栈的增长方向配置项目,那么今天bug菌就带大家了解一下栈的增长方向到底是咋回事。1、栈的增长方向首先我们要明确的是栈同样也是分布在我们的内存之中,而内存是通过地址来进行编排访问的,如下是堆栈的示意图:对于堆栈而言原本并没有方向一说,只有入栈和出栈一说,程序中执行push指令则栈顶向上移动,执行pop指令则栈顶向下移动,其仅仅只是一种先进后出的数据结构,增长方向都是从栈底向栈顶方向移动,即分配数据的过程。而我们平时所说的栈的增长方向又是怎么回事呢?为了在内存中分配一段内存给堆栈,我们必须要区分堆栈相对于内存的地址而言的方向性,通常栈顶增长的方向是从内存的低地址向高地址变化,我们则称为向上增长;反之则向下增长。所谓"水往高处流,即向上增长",这样应该就很好记忆了。2、有什么用?当了解处理器中栈指针的增长方向以后,我们在debug程序的时候才能真正的把控程序的运行过程。在移植RTOS的过程中我们都需要对每个任务的堆栈分配一个合适的连续内存区域来使用,此时初始状态堆栈指针指向什么位置就跟堆栈的增长方向密切相关,有过RTOS移植经验的朋友应该都有在RTOS配置项中关注过这块的选择。RTOS在任务初始化的时候,其堆栈指针应该指向其栈底位置,那么对于堆栈向上增长,任务初始化的时候我们需要把堆栈指针设置在所分配内存的低地址内存处,反之则设置到高地址处。设置好以后,其在堆栈分配的过程中才会朝着所分配的内存区域中,否则就会堆栈反向自爆,导致程序异常;如果你的堆栈分配不合理,同样了解堆栈变化方向后也变得有迹可循。同样在裸机程序中也需要了解一下处理器的堆栈变化方向,从而用来排查一些堆栈溢出所导致的程序异常问题。3、用C语言如何判断?要了解一个CPU的堆栈的变换方向,一方面就是查询相应的芯片参考手册,另外一方面就是实际测试了。毕竟堆栈也就是内存,自然就可以通过堆栈的分配过程取出所分配的内存地址来比较判断,而C语言可以方便的访问内存,也就比较容易判断当前处理器中堆栈指针的增长方向了。那还不简单,直接在函数内部先后定义两个局部变量,直接比较两个变量的地址大小不就搞定了吗?其实这种方式是依赖于编译器实现的,毕竟哪个变量先进行内存申请,并没有太大的影响。那么是否有一种方法不依赖于编译器实现呢?必须有的,那就是函数调用栈了,因为先调用的函数必然首先入栈。基于这样的思想,这里bug菌写一个判断堆栈增长方向的demo供大家参考: 1#include <stdio.h>2#include <stdlib.h> 3 4#define STACK_UP (0)5#define STACK_DN (1) 6 7/*************************************** 8@ Function: find_stack_direction 9@ Author  : bug man  10@ Note    : (公众号:最后一个bug) 11****************************************/ 12int find_stack_direction(int* ptr) 13{ 14    int  Val = 0; 15 16    printf("Last stack Addr : %p\n",ptr); 17    printf("Now  stack Addr : %p\n",&Val); 18 19    if(ptr > &Val) 20    { 21        return STACK_DN; 22    } 23 24    return STACK_UP; 25}  26/*************************************** 27@ Function: main 28@ Author  : bug man  29@ Note    : (公众号:最后一个bug) 30****************************************/ 31int main(int argc, char *argv[]) { 32    int  Val = 0; 33 34    printf("stack direction : %d\n",find_stack_direction(&Val)); 35    return 0; 36} 可以拿去试一试,看看你的芯片堆栈咋变化的~
栈的增长方向怎么理解?用C语言如何判断?
嘉立创PCB
pcb下单选项
家人们,今天准备用掉pcb彩色丝印卷,结果发现彩色丝印不能选择免费的客编或者二维码,只能啥也不加,这是为啥呀,工艺不支持嘛[疑问][疑问]
嘉立创PCB
老工程师总结的10条经验,太受益了~
1、你永远不可能什么都知道 2、好的团队可以让你的能力呈指数增长,而非线性增长 3、编写的代码应该便于阅读 4、耐心是你最好的朋友 5、持续性是关键 6、总是有比你优秀的人你可以向他学习 7、社交网络很重要 8、经常休息可以让你更高效 9、如果你希望在自己的职业生涯中更进一步,就需要有很好的人缘 10、大多数公司都不是你希望的样子
嘉立创PCB
【自制】超神奇的无线USB HUB!从此USB进入无线时代!
本项目的起因是要调试的嵌入式设备经常不在电脑旁边,搬来搬去的很不方便。所以萌生了想要实现把USB信号无线化的想法。项目主控使用全志H618,搭载linux操作系统,再运行一个VirtualHere软件,便可以实现USB信号完全无线化,再结合一些实用的USB HUB功能,从此USB设备将彻底摆脱束缚。
嘉立创PCB
嘉立创真是中国电子工程师的再生父母
嘉立创免费打板,EDA免费使用,3D打印免费打样,立创商城超级会员日每月一次下单立减,真是牛 #嘉立创PCB# #立创超级会员日#
嘉立创PCB
有没有什么办法增强焊盘的机械强度?
嘉立创PCB
趁着等快递的时间有完善了几个基础实用功能 1. (软件上的优化)16路实时逻辑分析仪 2. (软件上的优化)13路自定义函数发生器 3. (硬件上的优化)准备新开一块LVDS缓冲模块的板子 OwO...用原理图页写笔记这功能简直绝了
嘉立创PCB
相信大家对该通信的大部分基础理论知识已经了然如胸了,在开发过程中使用SPI通信问题应该不会太大,但SPI作为一种嵌入式工程师们如此青睐的通信方式,在开发中总会有人挖一些坑让你来填,当然这个人可能是自己。在定位这些问题的时候动不动就几天过去了,项目工程师又要来催了~那么今天bug菌根据以往的经验,将重点从通信的速度、容错性和结构这三个方面进一步谈谈SPI通信,也算是完结篇了。1、通信速度对于SPI通信并没有规范最高的通信速率,在我的开发经验中有见过达到50Mbit/s的应用场景,但通常比较常见的还是10Mbit/s左右。具体选用多快的通信速度,还得在实际项目中根据情况具体设计,比如:1、当前主从机的主频和项目的具体应用都与SPI数据的处理能力有着直接关系,一般SPI通信的时钟频率都是来源于主频分频,这就在一定程度上限制了其通信速率上限。即使能够达到较高速的速率,而处理器还需要处理更多的业务逻辑,再去处理SPI数据也是不够及时的,此时高速率并没有太大的意义了。2、SPI硬件PCB布线长度等等影响着线路阻抗,这也同样限制了通信速率,一般通信距离越长,通信速度越低,否则容易造成通信不稳定。特别是通信线路经过一些干扰源更是影响其稳定性,所以SPI作为一种相对高速的通信方式,一般都不会用于长距离通信中,而是大量用于微处理器与外部SPI接口的设备之间的通信,比如高速采样芯片ADC、处理器之间等等。3、前面说了即使SPI主机能够达到较高的通信速率,但从机主频或者数据处理能力不够,这样也是没有太大意义的,当你可以通过配置从机为接收队列或者DMA等方式进行优化,当然高速率在多机中能够减少同步延时。值得注意的是一些芯片标称的最高通信速率,是在比较好的外界条件下的测试值,超过了该标称值可能也能用,但并不会很稳定,容易导致通信异常。所以具体选用多快的通信速度,还需根据实际情况分析确认。2、容错性SPI不像IIC那样存在应答机制,也没有流控制机制,当从机配置较低,如果一个报文还没处理完,后一个报文又到来,导致传输错乱,其通信过程几乎都是靠硬件来保证数据的传输稳定性,是一种不可靠传输。当然如果是用于多机通信倒是可以通过制定可靠性校验协议来保证传输数据的稳定,但这也在一定程度上会降低通信的有效数据传输速度。像stm32的SPI外设发送和接收都存在独立的CRC校验功能,大致的原理就是使用CRC在每个位上进行串行计算,然后在最后一次数据传输结束时来传输CRC校验值,接受方接收到CRC以后自动拿着数据和CRC值进行比对,看是与否有数据故障,如果存在传输问题就会置位相应的CRC故障标志位告知。当然如果所选用的芯片SPI外设没有独立CRC模块可以模拟类似的操作进行处理,只是相对比较耗时,毕竟这个CRC得软件自己处理。stm32的SPI外设的灵活度远不止这些,比如配置成双线单向模式等,可以把MISO和MOSI都向一个方向传输,从而提高一倍的传输速度,感兴趣可以参考一下手册玩一下。3、通信模式SPI通信拓扑结构上的一大特色就是菊花链拓扑。上篇文章跟大家介绍的SPI一主多从的通信方式属于并行方式,要控制多个从机需要使用大量的GPIO信号来控制片选信号。似乎非常简约的SPI通信一下子变得不那么简单了,特别是布线方面是非常低效的,此时菊花链的通信方式便有了一席之地。菊花链模式下的SPI所有的片选和串联时钟信号都可以共用一条线,其数据以时钟节拍逐个bit的循环移动,从而完成数据传递,这样就大大减少了控制线路。当凡事总有其两面性,采用链式结构相对并联方式没有那么灵活,主机无法一次任意选中一个从机进行直接通信,而是得通过数据的循环传递。另外对于链式结构主从关系没有那么直接,相连接的从机之间存在着更多的依赖关系,一旦链路或者从机出现了问题,其影响是联锁的。菊花链的通信方式应用是非常多的,比如当我们在一块板上有多块控制芯片,但此时由于PCB大小的限制,可以选用菊花链的拓扑方式实现一个JTAG仿真器对多个JTAG芯片进行烧录和控制。
大话SPI通信--进阶避坑篇
嘉立创PCB
最近跟一个同事聊了聊天,他说一直用的位置式PID,从来没在具体项目中用过增量式PID,感觉两者没啥区别呀?于是跟他讨论了一番,不由得让人深思~1、“万能”的PIDPID是一种非常经典的控制类算法,凭着它的简单易用在工程上得到了广泛的应用,并且影响力也是极高,那为什么说其简单易用呢?可以说只要你对PID的主要的参数对系统的影响理解得足够好,完全可以通过手动试凑的方式来获得一套合适的PID参考,所以对一些非控制类的工程师应用起来也是非常友好的。当然还有一个非常重要的原因,PID算法对大部分系统稳定性、鲁棒性以及可靠性都非常的高,有调试PID控制算法经验的朋友应该都有类似的感觉,即便根据经验随便给系统一套参数都可以到达一个不错的控制效果。所以在很多人眼里这算法就是"万能的",适应的场景也非常的广泛,然而自古有一种规律"熊掌和鱼不可以兼得",PID算法虽然适应性非常广泛,对于处理一些特定的应用场景,或许其并不会最优的解决办法。基于大家在实际应用中各种各样的需求,曾经一个发展涌现了非常的PID的变种,也就是对PID算法在特定的应用场景进行优化、或者与其他一些控制方法进行结合,以便达到相应控制场景下的不错控制效果,比如微分先行PID、PID与智能控制的算法的结合等等。当然如果PID算法实在无法满足需求了,那也不能勉强,就只能考虑寻找另外更为匹配的控制策略,比如现在非常流行的自抗扰控制技术等等。2、PID的理解PID算法主要就是三项,比例(P)-积分(I)-微分(D),在连续的时间域内的表达式如下:从上面的公式可以看出PID算法是一个非常纯粹的数学表达式,既然是数学表达式那必然可以通过数学的方式进行分析,拉式变换一下,获得传递函数,然后采用控制理论分析方法,结合被控对象分析其对动态系统的稳定性、准确性以及快速性进行分析,从而达到性能上的最优解,这个控制系统的设计过程不是本文重点,暂时就不进行展开了。还记得最开始了解这个算法的时候,有一句话非常相信的彰显其魅力所在:P-I-D分别代表着当前、过去和未来。P对当前误差的抑制作用;I对历史误差的累积控制,以便消除静态误差;D根据误差的变化率进行补偿,从表达式也非常容易从根本上理解这几句话。3、数字PID在前面跟大家简单描述了连续域内的PID算法表达式,而连续域中该算法需要通过相应的模拟电路来进行实现,特别是一些没有数字芯片的嵌入式系统是经常可见的。但随着数字系统的应用,特别是单片机系统,数字PID更加得到广泛的应用,被大部分人所熟知的两种数字PID,分别是位置式PID和增量式PID。大部分的教材都会描述着两种形式的数字PID,然而这些教材一上来就介绍位置式PID与历史状态相关,过去会对现在的控制输出产生影响,而增量式PID仅仅只与最近的几次误差数据相关。如下是位置式PID表达式:这样看来增量式PID只与最近的两次误差有关系,不会存在累积误差的问题,说来增量式PID必然是更好的,那为何还要介绍位置式PID呢?也有伙计在自己的程序中使用增量式PID的表达式,毕竟增量式PID其输出仅仅只是控制量的增量,最后还是需要把输出量进行累积,这与位置式根本没啥区别。于是很多初学者,甚至一些用PID多年的工程师对此都抱有一丝疑问。其实这两种数字PID的应用场景是有区别的,增量式PID控制输出的仅仅只是控制量的增量,其主要是应用在执行机构带有积分部件的被控对象,而位置式PID其输出的是实际的控制量,则用于不带积分环节的执行机构。当然如果在一些不带积分环节的执行结构系统中你执意要使用增量PID的形式也无伤大雅,只是最后用数字积分进行处理后输出,其与位置式PID式没有差异,增量式PID的优势并没有展现,因为真正单独使用增量式PID的执行机构的积分环节是连续的,这是数字离散的方式无法比拟的。
不要只成为PID调参工程师
嘉立创PCB
如何在工程中添加说明文档
#嘉立创PCB# 请问在工程中添加说明文档,记录一些接口的说明,及工程中的注意事项,及修改的错误记录等,往高手指教
嘉立创PCB
1、#define与#undef今天分享一个C语言宏定义小技巧,从语法上来看比较简单,不过一旦真正领悟到其精妙之处不仅可以简化代码、还能提高代码的可扩展性。X-MACRO宏技术的核心在于灵活的应用#define与#undef,对于玩C语言的伙计#define是再熟悉不过了,但#undef却鲜有人在实际的开发过程中熟练使用,基本上都是#define走天下。那#define的作用域是怎样的呢?其作用范围都是从宏定义处到文件结束,不管函数内外均可以随意使用。那一不小心使用#define重复定义相同的宏又会怎样呢?对于大部分编译器会报重复定义警告,但也有小部分编译器采用最近的宏定义直接通过,所以稍不留神就把bug引入到了代码中。其实对于C语言编程素养良好的工程师们多会使用#undef来限制宏定义的作用范围,即取消宏定义,以免造成宏泛滥。 1#include <stdio.h>2#include <stdlib.h> 3 4#define HELLO_BUG   100 5 6int main(int argc, char *argv[]) { 7 8 printf("hello bug %d\r\n",HELLO_BUG); 9 10#undef HELLO_BUG 11 12 printf("hello bug %d\r\n",HELLO_BUG); 13 return 0; 14} 如上代码所示,便会编译报错,提示第二条打印语句HELLO_BUG宏未定义。2、X-MACROX-MACRO平时我们也叫"X宏",其实在bug菌之前的文章<三种管理C程序中标志位的方法,最后一种比较秀~>有一个简单的提及,今天单独拧出来简化讲讲。1#define X_MACRO(a, b)   a 2//do something 3#undef X_MACRO45#define X_MACRO(a, b)   b 6//do something 7#undef X_MACRO 如上是X-MACRO的比较精华的几句,通过#define与#undef的配合,可以使用相同的宏名称选择性的替换出我们想要的结构,从而达到简化代码的目的。同时我们也非常清楚,由于宏主要是靠编译器来处理,所以X-MACRO技巧也主要是在编译阶段来维护代码。下面来一波操作看看效果吧: 1/*************消息定义**********/ 2#define MSG_TABLE                  \ 3    X_MACROS(USER_MSG1, MsgProc1)  \ 4    X_MACROS(USER_MSG2, MsgProc2)  \ 5    X_MACROS(USER_MSG3, MsgProc3)  \ 6 7/*************消息枚举定义**********/ 8typedef enum { 9    #define X_MACROS(a, b) a, 10    MSG_TABLE 11    #undef X_MACROS 12    MSG_MAX  13} MSG_TYPE; 14 15/*************消息处理定义**********/ 16const Proc Proc_table[] = { 17    #define X_MACROS(a, b) b, 18    MSG_TABLE 19    #undef X_MACROS  20}; 21 22/*************实际使用**********/ 23void sMessageProc(MSG_TYPE msgtype) 24{ 25    (Proc_table[msgtype])(); 26} 当然X-MACRO还可以扩展多个参数来供序列化替换,同时X-MACRO宏定义也可以更加的复杂。比如使用#defineX_MACROS(a,b) #a宏来处理为字符串等。
C语言X-MACRO宏使用技巧
嘉立创PCB
1-32层pcb打样,真A级板材,最快12小时出货,自营制造,品质可靠!
推荐话题 换一批
#嘉立创PCB#
#DIY设计#
#畅聊专区#
#创享2025#
#嘉立创3D打印#
#嘉立创免费3D打印#
#618金豆嗨购节#
#高校动态#
查看更多热门话题
打赏记录
粤公网安备44030002004666号 · 粤ICP备2023121300号 · 用户协议 · 隐私政策 · 侵权举报 · ISO/IEC · Copyright © 2024 嘉立创社区版权所有
服务时间:周一至周六 9::00-18:00 · 联系地址:中国·深圳(福田区商报路奥林匹克大厦27楼) · 媒体沟通:pr@jlc.com · 集团介绍
移动社区