发动态
图文
列表
请问异型有铜槽孔怎么画?
嘉立创EDA
1、void 与 void*void表示的是无类型,不可以采用这个类型声明变量或常量,但是可以把指针定义为void类型,如void* ptr。void指针可以指向任意类型的数据,可用任意数据类型的指针对void指针赋值,比如int *ptrInt;void *ptrVoid = ptrInt ;指针的赋值可以认为是地址的传递,而一般的32位系统指针都是占用4个字节,所以指针赋值仅仅只是这4个字节的赋值与类型没什么关系。1void * memcpy( void *dest, const void *src, size_t len ); 2void * memset( void * buffer, int c, size_t num); 2、volatile关键字volatile修饰表示变量是易变的,编译器中的优化器在用到这个变量时必须每次都小心地从内存中重新读取这个变量的值,而不是使用保存在寄存器里的备份,有效的防止编译器自动优化,从而与软件设计相符合。3、数据占用大小数据占用大小是指不同的数据类型在平台中所占用的字节个数,不同的平台不同类型占用的字节个数稍有不同,不过在对应的平台进行开发过程中,必须要对每个数据类型的占用大小了如指掌,否则各种数据溢出,数据越界等等接踵而来。下面是简单罗列的一些数据占用情况:(在一般32位PC中)char8bitshort16bitint32bitlong32bitfloat32bitdouble64bit4、const与指针const是恒定不变的意思,与指针的结合主要的问题是其const在指针中的位置导致该变量属性不同。主要的识别办法是去掉数据类型,看const修饰的是哪部分。const int *ptr --> const *ptr -->那么const修饰的就是*ptr,而*ptr表示的是指针所指向内容,所以其总体也叫"常量指针"表示值无法改变。int *const ptr --> *const ptr -->那么const修饰的就是ptr,而ptr表示的是指针变量,指针变量的值就是地址,所以总体也叫"指针常量"表示地址无法改变。5、结构体与共联体对于结构体和共联体在嵌入式领域是使用得非常频繁的,一些可编程芯片提供的寄存器库都是采用结构体和共联体结合的方式来提供给软件人员进行开发,同时在平时的编码过程中这两个数据类型的灵活应用也能够实现代码更好的封装与简化。  如下面的简单示例,就可以非常灵活的访问Val中的bit位。 1typedef union 2{ 3    BYTE Val; 4    struct __packed 5    { 6        BYTE b0:1; 7        BYTE b1:1; 8        BYTE b2:1; 9        BYTE b3:1; 10        BYTE b4:1; 11        BYTE b5:1; 12        BYTE b6:1; 13        BYTE b7:1; 14    } bits; 15}BYTE_VAL, BYTE_BITS; 6、预定义标识符一般编译器都支持预定义标识符,这些标识符结合printf等打印信息帮助程序员调试程序是非常有用的,一般编译器会自动根据用户指定完成替换和处理。如下是常用的标识:__FILE__ :表示进行编译的源文件字符串;__LINE__ :表示当前文件的行号;__DATE__:表示文件日期;__TIME__ :表示文件时间;使用范例:1printf("file:%s\n line:%d \n data:%s \n time: %s \n",__FILE__,__LINE__,__DATE__,__TIME__); 7、#与###:是一种运算符,用于带参宏的文本替换,将跟在后面的参数转成一个字符串常量。##:是一种运算符,是将两个运算对象连接在一起,也只能出现在带参宏定义的文本替换中。1#define STR(s) #s  2#define COMB(str1,str2) str1##str2 3int main() 4{ 5    int UART1= 57600; 6    printf("%d\n", COMB(UART, 1));     7    printf("%s\n", STR(3.1415));      8    return 0; 9}
7个嵌入式C进阶技巧
嘉立创PCB
在嵌入式开发软件中回调函数是经常接触的一种软件设计方法,像我们的事件处理机制基本上都会使用到回调函数。那么就抽了点时间来聊聊他们:1、回调函数的理解在C语言中,回调函数其实与函数指针的调用在语法上并没有太大的差异,而为什么叫回调函数主要还是从功能上给它起的名字,即这个函数会被"返回来调用"。而这里所谓的“返回”就涉及到一个方向性问题,从哪里来到哪里去。而在软件中通常就是与“分层设计思想”挂钩的。在软件设计领域分层设计方式是非常广泛的,在嵌入式中最简单的分层就是两层"驱动层"和“应用层”。当函数功能上进行分层以后不应该直接在底层驱动中直接调用应用层函数等,比如应用程序通过调用驱动层接口获得物理量数据,我们常规的做法大部分都是不断的轮询相应的API接口返回数据,这样可能会导致不断的IO操作,效率相对比较低下。那么应用程序是否可以化主动为被动呢,一直舔狗实在是太累了?既然你现在不想搭理我,那等你准备好了,再来告诉我吧,到时候调用我给你的函数就可以了,这个函数已经放在了传给你的函数指针里了,那么这里应用程序所给的函数就是回调函数。比如我们经常会在应用程序中查询按键是否被按下,然后得编写一大堆的时序等等,还与应用逻辑耦合在一起。其实按键是是如何检测被按下的过程对于应用程序它并关心,底层程序查询确定好状态给应用程序一个是否按下的通知或者状态即可。此时底层按键检测程序要通知应用程序,就可以通过相应的回调函数来通知应用层并处理即可。如果还有点难理解,可以看看stm32使用hal库,你会发现在中断中有大量的回调函数指针被调用,其实回调函数的效果与中断服务函数的执行效果是类似的,hal库中使用回调函数的方式把中断的相关事件服务处理交给了用户自身来注册。把中断看成一种事件类型,那么回调函数的使用其实就类似于一种事件驱动机制。2、同步与异步调用首先要理清楚这两种方式需要理解什么是同步和异步。同步调用表示当调用一个底层接口,必须回调函数被执行完毕,不然该接口会一直处于堵塞状态没办法返回结果,且程序无法往下执行。异步调用表示当调用一个底层接口以后,不需要等待回调函数执行完毕,便可以直接返回继续做下面的事情,最终底层准备好以后便会执行回调函数处理应用层事务,所以我们也称这种回调函数为异步回调函数。而异步调用的好处在于调用函数不需要阻塞可以继续执行,从而大大提高程序运行效率,但由于异步回调函数在时间上是无序的,导致当我们需要异步调用函数能够顺序执行时便会存在难度,使得业务逻辑比较复杂,难以理解。为了保证回调的有序性,就需要以上一次回调的结果作为本次异步调用的条件,导致代码一层嵌套一层非常的冗长,类似于ifelse里面再嵌套ifelse之势,所以也很多人称这种方式为 Callback hell(回调地狱)。为了改善这种结构,通常会采用协程的概念去处理异步回调来规避该问题。对于异步调用常与多线程进行结合,在另外一个线程中执行异步操作,然后调用回调函数返回结果并继续处理。
回调函数、同步与异步调用
嘉立创PCB
本文主要是跟谈谈函数参数太多这个问题,其实应该早一点跟大家聊聊的,毕竟牵涉到软件代码的设计。主要还是因为平时很多话题写文章的时候又想不到,遇到了又不一定会想到要写到文章中去,所以迟迟没有涉及到。那么今天就针对函数参数数量问题做一个分析和编码建议:1、函数参数的传递既然本文谈到函数参数的个数问题,首先就需要了解函数参数到底是如何传递的,并且其影响着什么?函数的调用过程主要是依赖函数调用栈,对于栈的原理很简单-先进后出,而对于函数调用栈主要是在该栈中分配内存以供函数临时使用-(即压栈),而当函数返回便是一个栈回溯的过程-(即出栈)。所以函数的参数跟局部变量一样都分配到栈上,当然为了提高函数调用速度,相关变量会直接通过寄存器来传递,原理上也是类似的。在嵌入式开发中经常会有C语言与汇编语言相互调用的编码形式,这样就需要遵循一定的调用原则。对于使用甚广的ARM内核都遵循ARM过程调用标准APCS(ARM Procedure Call Standard)。该标准中规定了各种寄存器的使用限制、栈的使用规则、以及函数调用过程中的参数传递返回等,大家编程的时候可以参考相关ARM手册进行了解。对于函数调用优先会采用R0~R3传递参数,且不需要恢复,那么如果超过4个参数则只能通过栈来传递,相比寄存器传递需要耗费更多的时间压栈和出栈。所以这也是为什么有些人经常说函数参数最好不要超过4个或者过多的原因。2、参数太多引起的问题前面bug菌在谈及参数太多会导致函数调用更加的耗时,因为增加了参数入栈和出栈的时间,特别是一些循环语句中调用参数较多的子函数。而对性能上的影响,对于大部分朋友所做的项目可能并不是很在意,快点慢点也无所谓,一般用户也体会不到,毕竟现在的芯片性能都还不错,可以为低效的代码买单。但是参数太多对于编码风格却是大煞风景,更值得注意的是很容易让编码人员犯错。bug菌之前就遇到一种情况: 1void Function(int param1,int param2,int param3,int param4,int param5\ 2              int param6,int param7,int param8,int param9,int param10) 3{ 4 5    ...... 6} 7 8int main(void) 9{ 10    ...... 11 12    Function(Val1,Val2,Val3,Val4,Val5,Val6,Val7,Val8,Val9,Val10); 13    ...... 14} 如以上代码,由于参数太多,在传递参数的过程中,传递顺序不小心错乱了,编译仍然可以正常通过,但程序就引入了bug导致出错。3、如何处理函数参数那参数多少才算多?其实并没有严格的界定,因为最终大量的参数定义都会在栈上分配,只要不把栈撑爆了,都是允许的。对于C语言的参数传递,主要是两种方式,一种就是传值和传地址。如果一个函数内部不依赖于静态全局区参数或者函数外部存储区,数据均来源于函数参数,那么随着需求不断的变化,函数功能更加的丰富多变,参数也将随着变大。经常听有些朋友说直接把参数封装成结构体来进行传递,这样的处理虽然能够在一定程度上减少函数参数顺序错乱带来的风险,但与各参数分别传递并没有太大的改善。就类似于如下代码: 1void process(void) 2 3{ 4    sPara.m1 = 1; 5    sPara.m2 = 2; 6    sPara.m3 = 3; 7    sPara.m4 = 4; 8    ..... 9 10    process(sPara);     11} 同时我个人还是不建议简单地用来减少参数数量进行数据打包,结构体应当尽量表现业务上的关联性,当然如果你一定在数据之间强加一种关系,那我也没办法。同时一个函数一般只实现一种功能,不要把太多的功能放到一个函数中,一方面把函数写得特别长,另一方面就是会使得参数特别多,因为这些参数都和特定的功能相关。似乎单独值传递并不能直接改善参数太多带来的弊端。那么就必须借助函数以外的存储区来作为相关参数的存储位置,参数仅仅只是索引,更多的参数和信息还需要根据传递的地址或者是索引来获得,这样就降低了调用函数参数太多所带来的负担。以前也跟大家介绍过一些C语言面向对象程序的设计,所有的数据和方法都会封装到一个结构体对象中,这对于相关方法函数的调用只需要传递相应的对象地址给形参指针,一个指针多大?应该不用我多说了吧。当然也没有十全十美的事情,子函数引用函数以外存储区可能相对没有那么独立,因为外部存储区可能会发生参数变化,从而导致子程序运行结果发生变化,这一点是值得注意的,特别是对于多线程编程。
C程序这函数参数太多了,头皮发麻~
嘉立创PCB
最近工作上都无法用一个"忙"字来形容了,周天还在因工作上的一些事情加班,毕竟工作还是要放在首位,分享只能看成一种爱好。本篇文章主要是跟大家聊聊一个成熟项目中调试上位机的功能定位和职责划分:1、调试上位机的必要性 做嵌入式软件开发的朋友大部分时间都在跟底层驱动打交道,也基本上都是一些逻辑、算法或者策略等等。而一款与用户打交道的产品,为了更加直观和方便的给用户使用,基本上都离不开人机交互,像手持移动设备,往往都会有LCD等屏幕显示;工控行业的大型设备,一般都会与PC端桌面软件结合,也就是常说的上位机。然而这样的上位机涉及到桌面UI、数据库等等相关的技术知识,所以这样的项目至少也会有两拨人来共同开发,上位机和下位机。我们知道在嵌入式软件开发的前期都离不开各种仿真器,如果是嵌入式Linux会有比较成熟的终端或者调试手段那就不在这里讨论了。对于下位机部分基本都会采用仿真器来进行调试,相关驱动和环境部署好以后,就开始进行功能和算法的调试,在该过程中经常涉及到参数的整定、模式的切换、数据的采集获取、以及问题的定位,急需要一个更方便的动态方式来实现这些功能,那就借助调试上位机吧。调试上位机功能相对比较简单,主要就数据显示和参数下发,如果你想做得强大一点,可以做一些数据采集变换处理等等。然而大部分上位机的同事没有太多的精力帮忙开发这样一个调试上位机,又或者并不是太符合自己的调试需求,甚至还要经常修改。那就只能自给自足了,自己写上位机,所以项目实战经验多一点嵌入式工程师多多少少能够做一些桌面应用,比如用QT、C#等等。很多嵌入式工程师招聘的时候,能够懂一些PC端的桌面应用的开发,也是一项加分项,能够比较方便高效的进行下位机软件开发。2、问题所在与改善然而bug菌发现非常多项目的调试上位机千奇百怪,今天工程师A调试平台开发了一个上位机,然而过一段时间交接给工程师B来维护,又出现一个新的调试上位机,导致软件杂乱无章,能够写点桌面应用确实是一种能力的体现,但不对软件加以管束,只会对项目带来诸多的后遗症。下面谈谈一些看法:1、不要本末倒置之前看到一个同事对自己的调试上位机非常的在意,弄了各种UI美化等等,可是下位机软件写得一团糟。也能理解,每个人对赏心悦目的东西都会有一定的追求,但软件的本质都是一样的,更何况调试上位机的定位并不是给用户去使用,仅仅只是一种更加形象的表现嵌入式软件的方式。所以对于嵌入式工程师真的没有必要花太多的时间把专注点放在这个上面,而是应花更多的精力对下位机的逻辑、算法进行优化,增强其冗余性和稳定性。话说回来如果项目下位机的软件功能很简单,程序一烧录一把搞定,那真的就没啥可提升的了,倒可以根据自己所要发展得方向来学习。2、和用户上位机集成调试和用户上位机并没有什么区别,完全可以统一管理发布,只是非常多的软件项目负责人并没有权衡到系统的各个方面,当然也有做得不错的,比如非常多的软件都有两种管理模式,一种是用户模式,一种是开发者模式,可以通过设置密码来进行使用模式切换。专门的人做专门的事情,毕竟做上位机的同事对桌面应用的开发还是相对比较擅长的,只是对相关的调试需求并不是很熟悉,此时相应的嵌入式工程师应该把相应的需求整理设计清楚。整合成一个上位机,一方面能够进行较好的版本管控和功能的迭代。也不会经常出现到了现场解决问题忘记带调试上位机,又或者售后人员经常找你拿调试上位机等等麻烦。3、功能定位调试上位机,主要还是用于排查和定位问题。所以与调试上位机相关的交互和设计在下位机软件中不要杂糅在一起,以前同事负责一个项目,到客户现场经常出现问题,而在实验室却怎么也复现不了,后来对比发现在实验室他一直挂着调试上位机,因为调试上位机有定时发一些数据,导致现场不一致。所以一定要对调试部分功能上定位好,其主要功能就两部分,一方面是查看下位机运行的状态;另外一方面就是可以下发一些数据用于调试参数等等,也可以做一些更强的功能,比如波形分析等等,但都大同小异吧。在用户上位机正常运行的过程中,调试上位机依然能够正常获取状态和参数下发,所以不要有两个上位机只能有一个在线的互斥设计。这样黑箱子一样的下位机状态全部在调试界面暴露出来了,也基本没有什么bug能逃得出你的监视,相当于一个在线仿真器。
调试上位机也要好好管管~
嘉立创PCB
你好,我是猿java。这篇文章,我们来聊聊 Java 语法糖。什么是语法糖?语法糖(Syntactic Sugar)是编程语言中的一种设计概念,它指的是在语法层面上对某些操作提供更简洁、更易读的表示方式。这种表示方式并不会新增语言的功能,而只是使代码更简洁、更直观,便于开发者理解和维护。语法糖的作用:提高代码可读性:语法糖可以使代码更加贴近自然语言或开发者的思维方式,从而更容易理解。减少样板代码:语法糖可以减少重复的样板代码,使得开发者可以更专注于业务逻辑。降低出错率:简化的语法可以减少代码量,从而降低出错的概率。因此,语法糖不是 Java 语言特有的,它是很多编程语言设计中的一些语法特性,这些特性使代码更加简洁易读,但并不会引入新的功能或能力。#畅聊专区#那么,Java中有哪些语法糖呢?顺便吆喝一句,技术大厂跳板,前后端测试捞人,待遇还可以。Java 语法糖1. 自动装箱与拆箱自动装箱和拆箱 (Autoboxing and Unboxing)是 Java 5 引入的特性,用于在基本数据类型和它们对应的包装类之间自动转换。 // 自动装箱 Integer num = 10; // 实际上是 Integer.valueOf(10) // 自动拆箱 int n = num; // 实际上是 num.intValue() 2. 增强型 for 循环增强型 for 循环(也称为 for-each 循环)用于遍历数组或集合。 int[] numbers = {1, 2, 3, 4, 5}; for (int number : numbers) { System.out.println(number); } 3. 泛型泛型(Generics)使得类、接口和方法可以操作指定类型的对象,提供了类型安全的检查和消除了类型转换的需要。 List<String> list = new ArrayList<>(); list.add("Hello"); String s = list.get(0); // 不需要类型转换 4. 可变参数可变参数(Varargs)允许在方法中传递任意数量的参数。 public void printNumbers(int... numbers) { for (int number : numbers) { System.out.println(number); } } printNumbers(1, 2, 3, 4, 5); 5. try-with-resourcestry-with-resources 语句用于自动关闭资源,实现了 AutoCloseable 接口的资源会在语句结束时自动关闭。 try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) { System.out.println(br.readLine()); } catch (IOException e) { e.printStackTrace(); } 6. Lambda 表达式Lambda 表达式是 Java 8 引入的特性,使得可以使用更简洁的语法来实现函数式接口(只有一个抽象方法的接口)。 List<String> list = Arrays.asList("a", "b", "c"); list.forEach(s -> System.out.println(s)); 7. 方法引用方法引用(Method References)是 Lambda 表达式的一种简写形式,用于直接引用已有的方法。 list.forEach(System.out::println); 8. 字符串连接从 Java 5 开始,Java 编译器会将字符串的连接优化为 StringBuilder 操作。 String message = "Hello, " + "world!"; // 实际上是 new StringBuilder().append("Hello, ").append("world!").toString(); 9. Switch 表达式Java 12 引入的 Switch 表达式使得 Switch 语句更加简洁和灵活。 int day = 5; String dayName = switch (day) { case 1 -> "Sunday"; case 2 -> "Monday"; case 3 -> "Tuesday"; case 4 -> "Wednesday"; case 5 -> "Thursday"; case 6 -> "Friday"; case 7 -> "Saturday"; default -> "Invalid day"; }; 10. 类型推断 (Type Inference)Java 10 引入了局部变量类型推断,通过 var 关键字来声明变量,编译器会自动推断变量的类型。 var list = new ArrayList<String>(); list.add("Hello"); 这些语法糖使得 Java 代码更加简洁和易读,但需要注意的是,它们并不会增加语言本身的功能,只是对已有功能的一种简化和封装。总结本文,我们介绍了 Java 语言中的一些语法糖,从上面的例子可以看出,Java 语法糖只是一些简化的语法,可以使代码更简洁易读,而本身并不增加新的功能。——转载自:猿java
Java 语法糖,你用过几个?
开源硬件平台
在单片机应用程序开发中可能用得比较多有RS485,CAN通信等等相对简洁一点的总线,由于所选用的单片机性能和资源有限,以太网并没有在单片机应用中作为一种普遍存在的对外通信接口。但随着MCU工艺、性能的逐渐加强以及嵌入式Linux平台的推行,以太网通信也慢慢开始成为开发者们所考虑使用的一种可靠通信方式。经常有一些朋友问到,现在用不到技术和知识点是不是可以不用学?我只能回答:技术在不断的革新,并且总是朝着更加便利和通用化方向发展,现在看似非常复杂的技术,在以后的应用上都会得以简化,但即使再简化也还是需要有必备的一些基础和认识,所以总归还是要学的,至于什么时候学就看自己的时间精力了,当然越早学习,就越多一种选择。那么今天就浅谈一下TCP与UDP的区别与应用,并指引后续在系统通信设计上的设计考虑和选择。1、TCP VS UDP 要想在通信的两者之间合理的选择TCP还是UDP,首先需要理清楚两者的特点与区别,下面简单梳理一下:在学习这两种协议的时候你一定看到过这样中一句总结的话:"TCP是面向连接的可靠传输而UDP是无连接的不可靠传输。"其实这句话已经把这两种协议大部分特点都囊括在内了 :1、面向连接与无连接TCP在传输数据之前需要经过三次握手建立连接进行相互确认,当需要断开连接的时候需要进行四次挥手;而对于UDP就不需要这么繁琐的连接建立过程,直接传输即可。所以对于TCP仅仅只支持单播,只能点对点的在连接的两个端点中数据传输数据,不支持多播和广播;而对于UDP而言支持一对多、多对一和多对多的传输,这一点在通信架构设计中对这两种协议的选择非常重要,比如有些资源优先的MCU对socket连接有限等等问题。2、字节流与数据报UDP也称之为是用户数据报协议,而TCP为传输控制协议,所以UDP是一种面向应用报文的传输,有明显的传输边界,仅仅只是封包以后进行处理,不会进行合并和拆分,一次就传输一个报文。但是TCP是一种面向字节流的通信协议,没有明显的边界,其主要是保证数据正确且有序,TCP存在一个数据缓存区,如果数据量较大,其会进行分包发出,而当数据较少也会等待数据达到合适的数量后进行合并发送,所以会存在多个粘包的问题,这一点在设计中需要考虑。3、可靠传输TCP是一种可靠传输,确认重传、差错控制、流量控制和拥塞控制等等都是传输数据过程中实现的策略和算法,这就使得TCP能够达到数据上无差错、不丢失、不重复、有序。所以为了保证这些数据的可靠传输,TCP相比UDP的报文格式要复杂,且占用的资源也相对较多。而UDP则不同,它仅仅只是一种最大努力交付的协议,其主要是利用IP层的无连接传通信服务,可靠性方面它是无法保障的,有点类似于串口通信,它不需要连接,只管传输。如果你想让数据可靠,那么用户可以在应用层自己来增加可靠性传输策略和机制来进行实现,所以Udp传输数据是可能会丢失、无序。4、实时性UDP由于没有拥塞控制等等策略,协议上会轻量很多,其均以比较恒定的速度进行传输,不会出现发送速率降低的问题,所以在网络不好的情况下就丢包了。而对于TCP一旦有数据包丢失,就会进行重传等等一系列机制,传输速度大大降低。2、项目中该怎么选择?对于TCP和UDP的选择有些朋友在开发的时候比较纠结,因为有时候采用UDP和用户方面可靠的传输机制也能够达到TCP类似的效果,比如许多支持可靠通信的UDP库,所以具体怎么选择还是要根据具体的应用和设计。比如对于很多直播、游戏等等通过自己加入一些重传机制,可以最大可能的发挥UDP传输实时性的优点,使得呈现给用户更加流畅的画面体验。在嵌入式、物联网方面由于项目对实时性要求高,且资源有限,UDP相对比较轻量,也是较好的选择。但对于一些文字、文件的数据传输还是会优先使用TCP,毕竟TCP这块在保证数据的可靠性方面还是做得非常成熟,用户程序这块也可以减少一些可靠性处理。所以最终得选择,还是要结合TCP与UDP的特点和具体项目综合考虑。
UDP与TCP在嵌入式项目中该怎么选?
嘉立创PCB
1、!!操作看到交流群里有朋友抛出一段C语言操作:offset = len/64 + !!(len%64); 这两个连续的感叹号把有些人给整蒙圈了,还有些朋友调侃道: !!表示语气加重,事情非常紧急得尽快处理,可把我给整笑了。其实都是常规操作吧,只是这样的写法在正常的编码过程中并不多见。首先这两个!!并不是什么C语言新的关键字,而是!运算符的嵌套作用。!在C语言中叫逻辑非运算符,是一种条件运算符。语法形式 : !(条件) 其中的条件如果是false,则最终整个表达式为true;反之则为false,bug菌提醒一句:要与~进行区分,~是按位取反,很多初学者容易混淆。语法形式 : !!(条件) 所以如上表达式就是两个!的嵌套形式。当然如果你想项目代码中变得无可替代,可以继续如下操作:语法形式 : !!!......!!(条件) 前提是你要自己能看懂。那么回到!!,该操作所达到的效果便是条件逻辑与最终表达式的逻辑结果保持一致:!!(false) == false !!(非false) == true 而对于大部分编译器false对应的是0,而true对应的是1,所以很多同志拿着逻辑结果参与数值运算。offset = len/64 + !!(len%64); 该表达式的用处也非常清楚了,当len不能被64整除,则:offset = len/64 + 1; 获得正确的数据分组个数,这代码应该是来源于存储或者通信中。但bug菌觉得,尽量还是不要操作:逻辑和数值运算最好是分开,以增加代码的可读性和可移植性。2、还有个用处最早看到这种处理方式是在判断一个引脚的高底电平上:u8GPIOLevel = !!(GPIOA_Data &  PIN_2); !!在其中的作用跟之前是一样的,使得表达式的数据结果与条件中的逻辑保持一致,便可以直接获得结果。
C代码中看到"!!",捻了把汗~
嘉立创PCB
当嘉立创CNC将你的设计意图精准呈现,这份制造可靠性值得被看见!为此,我们推出了《晒单得无门槛研发补贴》活动——只需用镜头记录开箱瞬间,定格设计落地的惊喜,即可兑换CNC/钣金/复模加工专属无门槛券,最高260元/月!爆款视频再享额外补贴! 如何参与?三步轻松赢好礼! 【拍】拍摄开箱视频 收到嘉立创CNC、钣金或手板复模加工件后,尽情发挥创意!无论是拆箱展示、工件细节呈现、功能演示、应用场景还原,还是设计理念分享,只要能展现你作品的魅力,统统欢迎!视频参考示例如下: 8630521550027210752 【晒】带话题发布任一平台 将你的视频发布至以下任一平台:① B站 ② 抖音 ③ 微信视频号 ④ 嘉立创社区-CNC机械制造。 带上对应加工标签 #嘉立创CNC / #嘉立创钣金 / #嘉立创手板复模 并 @嘉立创CNC 官方账号 【领】扫码截图领补贴 发布完成后,找客服邀请进入活动群,提交作品信息(视频链接+订单编号+视频截图),审核通过后,专属无门槛券将自动发放至你的账户! 奖励多少?最高260元!爆款再加码! 本次活动设置了多种奖励,最高可得260元无门槛券还有额外惊喜相送,具体奖励规则如下: 【基础奖励】 所有合规内容经审核通过后均可获赠无门槛券,每周限领一次,每月可领4次。 CNC:分享可得20元无门槛券,每月可领4次,最高可领80元/月; 钣金:分享可得20元无门槛券,每月可领4次,最高可领80元/月; 复模:分享可得50元无门槛券,每月可领2次,最高可领100元/月; 【爆款奖励】 当视频到达播放量≥5000 且 点赞量≥50时,每10播放量1元物料支持,或每20播放量1元佣金,最高可获400元奖励! 温馨提醒:所有优惠券自发放日起30天内有效,请及时使用! 活动说明 【活动时间】 活动自即日起生效,结束时间另行通知。 【参与条件】 有效订单:通过嘉立创CNC官网(www.jlc-cnc.com)下单的CNC免费打样、CNC加工、钣金加工、手板复模 四类订单均可参与,其他订单类型暂不参与本次活动。 内容发布:发布作品时,务必带上对应业务话题#嘉立创CNC / #嘉立创钣金 / #嘉立创手板复模 并 @嘉立创CNC 官方账号,缺少标签或@将导致审核不通过。 实物一致:视频中展示的工件须与提交的订单信息保持一致。 诚信参与:严禁下单违禁品、发布违规内容、盗用他人作品、使用虚假订单号、同一视频重复提交等行为,一经核实将立即取消活动参与资格。 其他须知 内容授权:参与本次活动即视为授权嘉立创集团官方账号在合法范围内转载及使用您的作品(包括但不限于商业宣传)。 解释权:深圳嘉立创科技集团股份有限公司保留对本活动的最终解释权。 若在参与过程中有任何疑问,欢迎进群咨询,我们将竭诚为你解答。 评论有礼 你认为嘉立创CNC/钣金/手板复模加工服务体验过程中,最让你感到满意的地方是什么?评论区聊聊,截至2025年7月14日下午17:00,评论区点赞前十送嘉立创手板复模小兔叽一只! #嘉立创CNC# #嘉立创cnc晒单活动# #嘉立创cnc免费打样#
为设计成果证言,晒单最高可领260元无门槛优惠!
CNC机械制造
社区数据
今日帖子
-
今日互动量
-
在线人数
-
帖子总量
-
用户总量
-
推荐话题 换一批
#嘉立创PCB#
#DIY设计#
#畅聊专区#
#创享2025#
#嘉立创3D打印#
#嘉立创免费3D打印#
#618金豆嗨购节#
#高校动态#
查看更多热门话题
功能讨论
()
主题
打赏记录
粤公网安备44030002004666号 · 粤ICP备2023121300号 · 用户协议 · 隐私政策 · 侵权举报 · ISO/IEC · Copyright © 2024 嘉立创社区版权所有
服务时间:周一至周六 9::00-18:00 · 联系地址:中国·深圳(福田区商报路奥林匹克大厦27楼) · 媒体沟通:pr@jlc.com · 集团介绍
移动社区