搜索
bottom↓
回复: 17

C语言中使用if...else...和使用问号表达式的区别和联系

[复制链接]

出0入0汤圆

发表于 2017-10-24 14:39:29 | 显示全部楼层 |阅读模式
本帖最后由 擦鞋匠 于 2017-10-24 14:41 编辑

实验环境:
Keil MDK 5.14 + stm32f103

实验简介:
额,本人有一点代码整洁癖(只有一点点,说的更清楚点,我所谓的代码“整洁”,更多的是指代码“整齐“)。所以,对于比较简单的if...else...(类似大括号内只有一条简单赋值语句这种),我更倾向于使用问号表达式,因为更“整齐”。
如下代码1是C代码,代码2是if...else...部分的汇编,代码3是问号表达式部分的汇编。

代码1:
  1. int a, b, c, d, e, f=1, g=2;

  2. int add1(int x, int y)
  3. {
  4.         return x + y;
  5. }

  6. int add2(int x, int y)
  7. {
  8.         return x + y + 1;
  9. }

  10. int main(void)
  11. {               
  12.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  13.         delay_init();
  14.         uart_init(115200);
  15.        
  16.         printf("aaa");

  17.         if (a > 0)
  18.         {
  19.                 b = 2;
  20.         }
  21.         else
  22.         {
  23.                 b = 1;
  24.         }

  25.         d = (a > 0) ? 2 : 1;
  26.        
  27.         e = ((a > 0) ? add1 : add2)(f, g); //这样写的风险在哪里?为什么?
  28.        
  29.         printf("e = %d\r\n", e);
  30.        
  31.         while (1);
  32. }
复制代码


代码2
  1. 0x08000220 480A      LDR      r0,[pc,#40]  ; @0x0800024C //该语句的作用是什么
  2. 0x08000222 6800      LDR      r0,[r0,#0x00]
  3. 0x08000224 2800      CMP      r0,#0x00
  4. 0x08000226 DD03     BLE      0x08000230
  5. 0x08000228 2002      MOVS     r0,#0x02
  6. 0x0800022A 4909      LDR      r1,[pc,#36]  ; @0x08000250
  7. 0x0800022C 6008      STR      r0,[r1,#0x00]
  8. 0x0800022E E002      B        0x08000236
  9. 0x08000230 2001      MOVS     r0,#0x01
  10. 0x08000232 4907      LDR      r1,[pc,#28]  ; @0x08000250
  11. 0x08000234 6008      STR      r0,[r1,#0x00]
复制代码


代码3
  1. 0x08000236 4805      LDR      r0,[pc,#20]  ; @0x0800024C
  2. 0x08000238 6800      LDR      r0,[r0,#0x00]
  3. 0x0800023A 2800      CMP      r0,#0x00
  4. 0x0800023C DD01     BLE      0x08000242
  5. 0x0800023E 2002      MOVS     r0,#0x02
  6. 0x08000240 E000      B        0x08000244
  7. 0x08000242 2001      MOVS     r0,#0x01
  8. 0x08000244 4903      LDR      r1,[pc,#12]  ; @0x08000254
  9. 0x08000246 6008      STR      r0,[r1,#0x00]
复制代码


实验问题:
1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点效率根本就不重要),刨根问底来看,此处似乎使用if...else...效率更高,但是占用的flash也更多(编译产生的指令更多)。很多rtos源码如freertos等,基本不使用问号表达式,为什么?
2> 代码1注释语句,请问这样写逻辑不严密吗(之前看网上看资料,有人极其反对这种写法,但我不明白原因)? 为什么?
3> 代码2注释语句,该语句的作用是什么(我看汇编指令介绍,LDR一般都是相对于寄存器偏移,如LDR r0,[r1,#20],我不明白此处相对PC偏移有什么意义)?
恳请大神指教,不胜感激。。。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2017-10-24 15:17:40 | 显示全部楼层
为了可读性,我从不用问号表达式

出0入4汤圆

发表于 2017-10-24 15:45:08 | 显示全部楼层
还没用过这东东  - -

出0入0汤圆

发表于 2017-10-24 15:49:20 来自手机 | 显示全部楼层
实验问题:
1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点效率根本就不重要),刨根问底来看,此处似乎使用if...else...效率更高,但是占用的flash也更多(编译产生的指令更多)。很多rtos源码如freertos等,基本不使用问号表达式,为什么?
A:用不用条件表达式跟RTOS没有关系,就像你用不用RTOS跟条件表达式没有任何关系一样。或许你潜意识认为RTOS代码都很优秀,事实上并非如此。if是语句,?:是表达式,它们有各自的用途,在我的RTSS中经常用条件表达式。
   
2> 代码1注释语句,请问这样写逻辑不严密吗(之前看网上看资料,有人极其反对这种写法,但我不明白原因)? 为什么?
A:既然追求代码简洁,为什么还要用这样令人费解的写法?要知道,洁癖可是一种病。
   
3> 代码2注释语句,该语句的作用是什么(我看汇编指令介绍,LDR一般都是相对于寄存器偏移,如LDR r0,[r1,#20],我不明白此处相对PC偏移有什么意义)?
恳请大神指教,不胜感激。。。
A:该指令一般用来加载常数,所有的指令都是有意义的,你应该说“我不明白此处相对PC偏移有什么作用”
   

出0入0汤圆

发表于 2017-10-24 15:50:30 | 显示全部楼层
好像stm32的mcu对问号和分支中只有一条语句的if语句有特殊优化

出0入0汤圆

发表于 2017-10-24 15:59:24 | 显示全部楼层
同求   
不过我自己觉得如果if else 更多是条件判断    ?:更多是赋值表达式    功能方向不一样   但是某些情况下  结果是一样的  所以特殊情况下  看个人习惯了吧    就像 if else  和 case 一样
还请高手指点。。。。。

出0入0汤圆

 楼主| 发表于 2017-10-24 16:43:42 | 显示全部楼层
本帖最后由 擦鞋匠 于 2017-10-24 16:46 编辑
laoshuhunya 发表于 2017-10-24 15:49
实验问题:
1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点效率根本就不 ...


首先,感谢大神指教

1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点效率根本就不重要),刨根问底来看,此处似乎使用if...else...效率更高,但是占用的flash也更多(编译产生的指令更多)。很多rtos源码如freertos等,基本不使用问号表达式,为什么?
A:用不用条件表达式跟RTOS没有关系,就像你用不用RTOS跟条件表达式没有任何关系一样。或许你潜意识认为RTOS代码都很优秀,事实上并非如此。if是语句,?:是表达式,它们有各自的用途,在我的RTSS中经常用条件表达式。
B:也就是说,不见得使用问号表达式就是一种不好的编程习惯,这点我非常赞同大神,否则,C语言可能早就放弃它了。
   
2> 代码1注释语句,请问这样写逻辑不严密吗(之前看网上看资料,有人极其反对这种写法,但我不明白原因)? 为什么?
A:既然追求代码简洁,为什么还要用这样令人费解的写法?要知道,洁癖可是一种病。
B:因为在某些情况下,会写出非常“整洁”或者“整齐”的代码(形式上整齐,实现结果也正确,关键也看不出逻辑不严密啊)。
   
3> 代码2注释语句,该语句的作用是什么(我看汇编指令介绍,LDR一般都是相对于寄存器偏移,如LDR r0,[r1,#20],我不明白此处相对PC偏移有什么意义)?
恳请大神指教,不胜感激。。。
A:该指令一般用来加载常数,所有的指令都是有意义的,你应该说“我不明白此处相对PC偏移有什么作用”
B:大神说的没错,我的确是这个意思,那大神能帮忙分析下此处使用PC跳转实现的原理吗?

出0入475汤圆

发表于 2017-10-24 17:25:20 来自手机 | 显示全部楼层
我的满篇基本上是if,else。因为我连那个问好的语法都看不懂,甚至switch都很少用,不好意思的掩面...

出0入0汤圆

发表于 2017-10-24 18:00:20 | 显示全部楼层
擦鞋匠 发表于 2017-10-24 16:43
首先,感谢大神指教

1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点 ...

3> 代码2注释语句,该语句的作用是什么(我看汇编指令介绍,LDR一般都是相对于寄存器偏移,如LDR r0,[r1,#20],我不明白此处相对PC偏移有什么意义)?
恳请大神指教,不胜感激。。。
A:该指令一般用来加载常数,所有的指令都是有意义的,你应该说“我不明白此处相对PC偏移有什么作用”
B:大神说的没错,我的确是这个意思,那大神能帮忙分析下此处使用PC跳转实现的原理吗?
A:如果一条32位指令要加载一个32位立即数,显然,指令编码中放不下这么大常数,汇编器就会在这条指令邻近的地方找个位置存放这个常数,并且计算相对于该指令(PC)的地址偏移,然后从偏移地址处加载数据。如果加载的目标是程序计数器PC,则会引起程序跳转。
   

出0入0汤圆

发表于 2017-10-24 18:03:20 | 显示全部楼层
擦鞋匠 发表于 2017-10-24 16:43
首先,感谢大神指教

1> 我容易纠结if...else...和问号表达式到底谁的效率更高(尽管我也明白,纠结这点 ...

反对这种写法的,应该是可读性的原因,至于严密性,没什么讲究。

出0入0汤圆

 楼主| 发表于 2017-10-24 22:29:21 | 显示全部楼层
laoshuhunya 发表于 2017-10-24 18:00
3> 代码2注释语句,该语句的作用是什么(我看汇编指令介绍,LDR一般都是相对于寄存器偏移,如LDR r0,[r1, ...

再次感谢大神。。。

出0入0汤圆

发表于 2017-10-24 23:47:24 来自手机 | 显示全部楼层
没有好不好,看看在什么场合应用了。

出0入0汤圆

发表于 2017-10-25 08:28:32 | 显示全部楼层
是个好话题  
我一直以为 是一样的 只是这法不同.这得了解编译器.   看生成后的代码不同  , 代码优化过吗?
switch  if else   A?1:0 这三种 都可以达到一个目的     
SWITCH   case x 只能是常量   后面二种可以是变量   

有时为了追求速度 还真得追究一下 到底有什么区别

看汇编肯定 ? 号的效率高一些  我不太习惯用这种 .

出0入0汤圆

发表于 2017-10-25 08:55:47 | 显示全部楼层
javenreal 发表于 2017-10-24 15:50
好像stm32的mcu对问号和分支中只有一条语句的if语句有特殊优化

如果不开条件编译优化选项是不会有加成的,mdk下叫做优化以速度优先

出0入8汤圆

发表于 2017-10-25 08:57:48 | 显示全部楼层
wind2100 发表于 2017-10-25 08:28
是个好话题  
我一直以为 是一样的 只是这法不同.这得了解编译器.   看生成后的代码不同  , 代码优化过吗?
...


楼主位的汇编代码,是没有优化的。
编译器是对于 C 代码是直译的,木有润色。if 语句中,就相应出现了两句对于存储器的访问(对 b 的赋值)。

相应的,开启优化选项的话,最终,这两种写法,在汇编的呈现上,应该是没什么差异的,否则,这编译器也弱了点。

至于楼主位的其他问题:
1、代码 1 的写法,此种场景,可读性不强。
2、代码 2 的 LDR 语句,这你需要去看书、看书、看书,重要的事情说三遍。

出0入0汤圆

发表于 2017-10-25 09:15:48 | 显示全部楼层
wind2100 发表于 2017-10-25 08:28
是个好话题  
我一直以为 是一样的 只是这法不同.这得了解编译器.   看生成后的代码不同  , 代码优化过吗?
...

不一定的  问号表达式并没有一定比if else快的道理, 怎么安排还是编译器说了算

就像switch case结构,是不是一定比if else快呢,不好说,还是看编译器安排,有可能会被优化成if else结构

至于if else结构是不是可能被优化成switch case结构,这个好像没见过

出0入0汤圆

 楼主| 发表于 2017-10-25 22:26:58 | 显示全部楼层
security 发表于 2017-10-25 08:57
楼主位的汇编代码,是没有优化的。
编译器是对于 C 代码是直译的,木有润色。if 语句中,就相应出现了两 ...

感谢大神指教。
额,这段代码的确是没有开启优化,主要是为了方便和汇编代码做比较。


回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 07:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表