PROCESS_YIELD()宏和C语言的switch语句< contiki学习笔记之七>

2023-05-16

      写在前面:  按照main()函数的代码一行一行的分析,该是看到了 etimer_process 这个位置。但是etimer_process实现里的一个宏 PROCESS_YIELD()引出了很多故事,于是单独把整个宏的东西整理成笔记,贴出来,和学习contiki的伙伴分享。

    在说这个宏之前,得先记下c 语言的switch()遭遇。

    switch()从表面上来看,或许应该是非常简单的问题--C语言的基本功吧。它的使用方式,按照常规来说,如下图所示:

好吧,那就贴一段常规的代码:


 1 int main(void)
 2 {
 3     int k = 1;
 4     switch(k) {
 5         case 0: printf("good job!\n");break;
 6         case 1: printf("hello world!\n");break;
 7         default:break;
 8     }
 9     return 0;
10 }  

很规矩的一段switch()的代码,几乎是所有C语言书上的教程。输出结果就不再说了。Hello world 嘛。

再来看一段:


 1 int main(void)
 2 {
 3     int k = 1;
 4     switch(k) {
 5         case 0:
 6             do{
 7                 printf("good job !\n");
 8                 case 1:                     printf("Hello world!\n");
11                 }while(0);
12             };
13             return 0;
14 }  

这段呢? 能编译通过吗?能执行吗?或者,结果如何?

在QQ群里问了一些,众说纷纭,其中有怀疑者,有否定者,还有猜测者。最难堪的是,有大牛知道这个程序的原理,然后直接让我看C语言书..  

在这种鄙视下,果断的使用以下这个命令:


gcc -S test.c  

生成了 test.s文件

打开如下:


 1     .file    "test.c"
 2     .section    .rodata
 3 .LC0:
 4     .string    "good job !"
 5 .LC1:
 6     .string    "Hello world!"
 7     .text
 8     .globl    main
 9     .type    main, @function
10 main:
11 .LFB0:
12     .cfi_startproc
13     pushq    %rbp
14     .cfi_def_cfa_offset 16
15     .cfi_offset 6, -16
16     movq    %rsp, %rbp
17     .cfi_def_cfa_register 6
18     subq    $16, %rsp
19     movl    $1, -4(%rbp)
20     movl    -4(%rbp), %eax
21     testl    %eax, %eax
22     je    .L3
23     cmpl    $1, %eax
24     je    .L4
25     jmp    .L2
26 .L3:
27     movl    $.LC0, %edi
28     call    puts
29 .L4:
30     movl    $.LC1, %edi
31     call    puts
32 .L2:
33     movl    $0, %eax
34     leave
35     .cfi_def_cfa 7, 8
36     ret
37     .cfi_endproc
38 .LFE0:
39     .size    main, .-main
40     .ident    "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)"
41     .section    .note.GNU-stack,"",@progbits  

      好吧,简略的说下这个汇编代码,其中 .LC0  .LC1里面放了我们要打印的字符串。第10行开始是main()的入口地址。然后下面的第26行.L3 和第29行.L4,就是分别打印了.LC0和.LC1里面的字符串。

      像C语言一样,从Main()开始看吧 <中间杂乱的就略过了>,

      第21行, testl 指令开始测试 %eax是正数负数还是0,然后下一条  je  指令,在汇编中表示相等/为0   的话就跳转到某个地方去,这里就跳转到.L3里面去。  

      第23行,cmpl 指令,就是检测  %eax 寄存器的值是否为 1,。若是,则跳转到某个地方去,这里就跳转到.L4里面去。

      第31行和36行,都call 了 puts函数,其实就是gcc 把printf()偷换成了puts吧。

      解释的就这么多,其他无非就是push  pop的操作。这是汇编最爱干的事情。

      另外就是,上面的解释中,不断的使用了 "跳转" 一词,那么,还有一个关键字,在C语言中也是跳转功能,那就是 goto。

     那么,按照上面的思路来说,switch()语句的底层实现,其实就是一个goto原理:先是判断一个值,然后根据这个值跳到某个地方去,这个地方用标签标出来。那么switch(k)这个时候就是在对值进行判断,case 就是那个标签,至于其中goto 被隐含了。一般的人不知道,但是编译器知道---这就足够了。

    一言以蔽之: switch() = 判断 + Lable + goto. --->case语句随便写在switch(){}里面的某个位置,都无所谓了(如果没有break 和return的话)。

    那么,这还是教科书上的switch()吗? 答案有待商榷。但是,按照这段汇编,我们上面那段怪怪的C语言,结果有了,当K = 1的时候,"Hello world";当k = 0的时候,"good job"  "Hello world". 现在是case 0语句里面套了一个case 1语句,若有兴趣,可以在case 1里面再套一个case 2子句,然后把k = 2 看看结果如何....

 

好吧,switch()就先说在这里。接下来看PROCESS_YIELD()宏的展开。

--------------------------------------------------------------------------------------------------

PROCESS_YIELD()宏

contiki/./core/sys/process.h:


1 #define PROCESS_YIELD()             PT_YIELD(process_pt)  

PROCESS_YIELD 被 PT_YIELD替换掉:

PT_YIELD(pt)

contiki/./core/sys/pt.h


1  #define PT_YIELD(pt)                \
2    do {                      \
3      PT_YIELD_FLAG = 0;              \
4      LC_SET((pt)->lc);               \
5      if(PT_YIELD_FLAG == 0) {            \
6        return PT_YIELDED;            \
7      }                       \
8    } while(0)  

先把其中的 LC_SET()宏也打开吧:

contiki/./core/sys/lc-switch.h


1  #define LC_SET(s) s = __LINE__; case __LINE__:  

回溯一下,PROCESS_YIELD()宏被替换成这个样子:


1             do {
2                 PT_YIELD_FLAG = 0;
3                 (process_pt)->lc = __LINE__;
4                 case __LINE__:
5                     if(PT_YIELD_FLAG == 0) {
6                         return PT_YIELDED;
7                     }        
8             }while(0);      

说明:

 PT_YIELD_FLAG 这个是在 PROCESS_BEGIN()宏中的产物,一个char 型变量,在PROCESS_BEGIN()中被初始化成了 1。当然在PROCESS_END()里面也有它,并把它置为0了。当然,在PROCESS_YIELD()这里也有它。

(process_pt)->lc = __LINE__;  就是把程序当前行给保存下来了。<但并没有保存现场>

case __LINE__:  这个肯定要和switch()配合用,而且,当switch()的测试值为这个 __LINE__的时候,就跳到这个case里面去执行。

if(PT_YIELD_FLAG == 0) {
return PT_YIELDED;
}

这就没解释的必要了,无非就是在某种条件下,是继续执行程序还是直接返回去了。

 

但,就上面展开的8行代码,铺陈开了故事的所有脉络....

 

关键字:  contiki  switch 汇编

 

 

 

    

转载于:https://www.cnblogs.com/chineseboy/p/3870822.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PROCESS_YIELD()宏和C语言的switch语句< contiki学习笔记之七> 的相关文章

  • Swap Nodes in Pairs

    Given a linked list swap every two adjacent nodes and return its head For example Given 1 gt 2 gt 3 gt 4 you should retu
  • Redis

    介绍 官网 xff1a http redis io Redis是一个开源的使用ANSI C语言编写 支持网络 可基于内存亦可持久化的日志型 Key Value数据库 xff0c 并提供多种语言的API 从2010年3月15日起 xff0c
  • 转 C++常用的类库

    1 系统和网络编程库 xff1a ACE 除了ACE之外 xff0c 还有很多系统和网络编程方面的程序库 比如在线程库方面 xff0c 还有ZThread boost thread xff0c 如果放大到C C 43 43 领域 xff0c
  • Linux零碎记录之ulimit【堆栈大小、stack size、进程数限制、文件句柄限制、linux用户空间限制】...

    写了个小程序 本来打算写个hash表的 xff0c 但是出现 段错误 include lt stdio h struct a char a 4096 char a1 4096 char a2 4096 char a3 4096 int ma
  • 串口扫盲十一:RS-232至RS-485RS-422接口的智能转换器

    摘要 详细地介绍了如何从RS 232信号线上高效率地产生电源 如何实现RS 232接口与RS 485RS 422接口的智能转换 同时 也给出了具体的硬件设计及软件设计方法 关键词 RS 232 RS 485RS 422 接口 智能转换器 随
  • strcpy()/strcat()

    为什么80 的码农都做不了架构师 xff1f gt gt gt char p1 15 61 34 abcd 34 p2 61 34 ABCD 34 str 50 61 34 xyz 34 strcpy str 43 2 strcat p1
  • 路由器逻辑接口配置总结

    逻辑接口配置 1 Loopback接口配置 Loopback 回环 接口是完全软件模拟的路由器本地接口 xff0c 它永远都处于UP状态 发往Loopback接口的数据包将会在路由器本地处理 xff0c 包括路由信息 Loopback接口的
  • 联合体、结构体简析

    1 联合体 结构体定义 联合体 xff1a 在进行某些算法的C语言编程的时候 xff0c 需要使几种不同类型的变量存放到同一段内存单元中 也就是使用覆盖技术 xff0c 几个变量互相覆盖 这种几个不同的变量共同占用一段内存的结构 xff0c
  • tcpdump抓包命令

    该命令是抓包分析工具 xff0c 可以将数据包的头或者是整个包抓取下来进行分析 xff0c 支持针对特定协议 主机进行过滤 xff0c 同时支持逻辑操作 抓取本机第一个网络接口通常是eth0上所有的包 tcpdump 抓取指定指定网卡上的的
  • rundll32.exe命令使用大法

    lt DOCTYPE html PUBLIC WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml strictdtd gt Rundll32 exe是什么 xff1f 顾名思意 xff0c 执行3
  • sftp

    引述自 xff1a http cs ecust edu cn snwei studypc oftencommand ftp htm sftp的命令格式为 xff1a sftp v d i n g hostname v 显示远程服务器的所有响
  • L298N接线图

    转载于 https my oschina net surenpi blog 481745
  • 大数据:Hive - ORC 文件存储格式

    一 ORC File文件结构 ORC的全称是 Optimized Row Columnar xff0c ORC文件格式是一种Hadoop生态圈中的列式存储格式 xff0c 它的产生早在2013年初 xff0c 最初产生自Apache Hiv
  • WPF RichTextBox 禁止换行

    原文 WPF RichTextBox 禁止换行 这个问题困扰了好久 xff0c 进过不断的努力 xff0c 终于解决了 lt RichTextBox Margin 61 34 0 44 10 0 34 Name 61 34 codeText
  • 浅谈微信小程序用setStorage和getStorage缓存和获取数据

    缓存数据 每个微信小程序都可以有自己的本地缓存 xff0c 可以通过 wx setStorage xff08 wx setStorageSync xff09 wx getStorage xff08 wx getStorageSync xff
  • 微信扫码登录是如何实现的?

    网页版微信刚推出时 xff0c 无数人被它的登录方式惊艳了一下 xff0c 不需要输入用户名密码 xff0c 打开手机微信扫一扫 xff0c 便自动登录 从原理上讲 xff0c 二维码只能是一段文本的编码 xff0c 如何用它实现快捷登录的
  • python - http请求带Authorization

    背景 接入公司的一个数据统计平台 xff0c 该平台的接口是带上了Authorization验证方式来保证验签计算安全 方法 其实很简单 xff0c 就是在header中加入key 61 Authorization xff0c value是
  • element设置设置日期0点到23:59:59

    2019独角兽企业重金招聘Python工程师标准 gt gt gt js方式 var start 61 new Date new Date new Date toLocaleDateString getTime 当前日期0点到23 xff1
  • 一张图看懂亮度、明度、光度、光亮度、明亮度

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 亮度 明度 光亮度 xff0c Luminance和Brightness lightness其实都是一个意思 xff0c 只是起名字太难了 提出一个颜色模型后 xff0c
  • prfpset文件怎么导入pr?pr预设如何导入?

    prfpset文件是一种可以导入到Adobe Premiere Pro中使用的预设文件 xff0c 导入后即可为你的画面进行调色 xff0c 不同的pr预设拥有不同的调色效果 xff0c 那么prfpset格式预设怎么打开 xff1f pr

随机推荐