|
C语言会同意一些"令人震惊"的结构,下面的结构是合法的吗,我们来看看几个例子。 c = a+++b;以下代码是合法的吗,咋的一看不禁有这样的疑问? int a = 5, b = 7, c;c = a+++b;0 Q8 z& k# e$ k$ `/ x% p7 Z 这个代码确实不咋符合习惯的写法,但是不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它? 根据最处理原则,编译器应该能够尽可能处理所有合法的用法。因此,上面的代码会被处理成: c = a++ + b;$ N8 ~/ l; |8 A4 j, `我们来测试一下: //https://tool.lu/coderunner///来源:技术让梦想更伟大 //作者:李肖遥 #include <stdio.h> H6 l! P& @. E% h. v- h' u5 L- H: c int main() { int a = 5, b = 7, c; c = a+++b; printf("a = %d,b = %d,c = %d",a,b,c); return 0; A5 Y+ s1 t1 h s1 W" u2 N } 输出结果如下:
其执行顺序:
上面那么可能只是开胃菜,那么这个表达式呢,有什么想法?咱们二话不说,直接上代码测试。 //https://tool.lu/coderunner///来源:技术让梦想更伟大5 [: Z3 y& p& H1 Y( E, N //作者:李肖遥 #include <stdio.h> - Z, M3 b" Y0 y$ y F: s int main()/ [ J1 z" l) x# F% O {% m3 b) ~7 i+ z# |# B% K# e int a = 5, b = 7, c;5 l+ @# n8 _" I+ L c = a+++++b; //c = (a++) + (++b); //c = ((a++)++) + b;6 H% D- \* o, V) h: t printf("a = %d,b = %d,c = %d",a,b,c); return 0; }: z6 f" |1 X: H7 w- q) | 编译结果如下:
虽然一看就知道意思是(a++)+(++b);,但是编译就通不过,我们把括号加上,c = (a++) + (++b);,编译通过,那么出错信息大概是:括号影响了优先级?我们从侧面以及原理来解析一下。 侧面解析一下对于a+++++b这一段代码,编译系统从左至右扫描整条语句,先遇到a++,判断出来是一个a的后缀自加运算; 然后接着扫描,遇到一个+,+是一个二目运算符,它的左边已经有一个运算数a++了,系统就向右搜索第二个运算数; 又遇到一个+,++比+的运算级别要高,这时,编译系统就将两个+看成一个整体来处理; 既然是++,编译系统就认定,肯定它的左边或右边有一个变量,编译系统先搜索左边,发现++,不是变量; 再搜索右边,发现+b,+b是什么东西?编译系统是无法搞明白的; 因此它就认为++是一个缺少左值的自增运算符,于是提示错误给用户:lvalue required as increment operand 原理解析一下C语言在这里遵循词法解析的贪婪匹配原则。优先匹配尽可能多字符的符号,无论是否有语法错误(因为词法分析时还没有语法检查)。 于是a+++++b会被当作a ++ ++ + b,这是非法的表达式,因此产生编译错误。 这个问题在ISO C99标准中直接以示例描述,原文如下: “那么,也许是c = ((a++)++) + b;这个意思呢? 我们编译结果依然报错,如下:
这涉及到“左值”的问题。百度百科定义如下: “ 总结:a存在左值,可以有表达式:a++。但是(a++)不存在左值,无法继续执行(a++)++操作,所以最终报错。 怎么样才能编译正确呢?a+++++b在编译时会报错,那么a++ + ++b呢?来看以下代码: //https://tool.lu/coderunner/5 l. X. n& g9 } D$ \2 {//来源:技术让梦想更伟大/ {6 d" K5 k, v( O //作者:李肖遥 #include <stdio.h> int main() { int a = 5, b = 7, c;; I0 f$ A( K( I# T# g2 ? c = a++ + ++b; printf("a = %d,b = %d,c = %d",a,b,c);9 H' ~0 o5 M' | return 0; } 结果如下:
其代码与c = (a++) + (++b);结果一样,说明是正确的,其按照下面顺序执行:
这个表达式看着爽不爽?我们知道自增自减运算,表示对自身进行a=a+1或者a=a-1的运算。 ++a表示在调用前就a+1,a++表示在调用后+1。 int c=(++a,b++,a++,++b);这个逗号隔开的表示用最后一个式子对C进行赋值,测试如下: //https://tool.lu/coderunner/% G. d- L9 i! t" Z//来源:技术让梦想更伟大- x+ Z0 c4 i5 y( B( E6 c //作者:李肖遥& L5 B+ R/ F7 k( k % N: [3 F9 @& i! o& L, e! U* k #include <stdio.h>; ^" f( \0 r; ~- o/ {; _ int main() { int a = 5, b = 7, c;' B2 W' a% K& A/ [5 n c=(++a,b++,a++,++b);' [, z+ ^* e) L z/ g3 K printf("a = %d,b = %d,c = %d",a,b,c);1 J/ J4 A/ `! T return 0;# H" T3 h: } G/ A% b }% p% `- E$ v! v4 k) Y 输出的结果如下:
这段执行的顺序如下
我们看到这些有趣且不常见的代码的时候,无需怀疑,只需要根据经验一步一步分析,就会发现其中的玄妙之处。在此我总结以下几点。
|
| 我从来不这么干!不给自己个别人找麻烦! |
这种装模作样的代码语法就国人喜欢拿来装逼用而已,代码是拿来阅读改进的,浪费时间去增加阅读难度还不如好好想想你的应用逻辑怎么改进优化 |
【STM32H5 评测】基础硬件加密与随机数性能 - STM32H5E5实测硬件AES加解密、HASH运算、TRNG真随机数输出速率与稳定性
【STM32H5 评测】NUCLEO-H5E5ZJ 使用 TrustZone 安全分区系统实践测试
【STM32H5 评测】CPU核心性能 - STM32H5E5跑 RTOS,观察任务切换速度、中断响应快慢
【STM32H5 评测】内存读写性能 - STM32H5E5实测Flash,SRAM读写速度,用DMA搬运大块数据
【NUCLEO-C562RE】OLED 显示
保姆级教程:CMake 工程导入 STM32CubeIDE 步骤
STM32CubeCLT 1.22.0新版本发布
【下载问题解决】关于ST官网下载软件问题解决
【STM32H735G-DK测评】lvgl移植
【STM32H735G-DK 测评】STM32H735G-DK External Loder 编译和测试
微信公众号
手机版