查看原文
其他

【系列】嵌入式编程"进阶有道”之C程序(2)

bug菌 最后一个bug 2021-01-31

1、日常聊一聊(听说文章与音乐更配)

    文章开头为大家选了一首JJ比较老的一首歌《江南》,大家可以重温一下。前天该系列的第一篇文章简单讲了一下C语言转化到机器码的一个过程,然后为大家整体描述了一下为什么底层开发选择C语言等等,该系列文章可能知识点都比较分散,都是一些C语言编程中的小细节,每个小细节又不足以写成一篇独立的文章,所以这个作者以这种形式把小的知识点进行collect,然后以小标题的形式给大家介绍,如果是C语言的大型知识点肯定就独立成文章分享给大家,就不会在该系列文章中呈现。

    好了,下面开始进入今天的主题:

1、各式各样的main函数

    细心的小伙伴应该注意到我们的main函数的形式还是挺多样的,比如说void main(void);int main(void);int main(int argc,char *argv[]);等等,main函数的不同形式大部分跟编译环境有关系,对于大部分单片机系统都是不带参数不带返回值,而对于有OS的系统中运行应用程序一般都是带参数和带返回值的形式,一方面父进程可以为其提供参数,同时其返回值可以反馈出其运行状态,比如说我们linux中或者Windows中的DOS命令等。

    那么我们可以来了解一下int main(int argc,char *argv[])这种形式的参数,其他的形式的void仅仅是为了限制参数的传入与返回。main函数本质上来讲和其他普通函数是一样的,不过在我们命令行运行对应的程序的时候传入参数有所区别,比如下面我在windows下面运行的示例:

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. /*********************************************

  4. * Fuction:main

  5. * Author : (公众号:最后一个bug)

  6. ********************************************/

  7. int main(int argc, char *argv[]) {

  8. int i = 0;

  9. printf("argc:%d\n",argc);

  10. for(i = 0;i < argc;i++)

  11. {

  12. printf("argv[%d]:%s\n",i,argv[i]);

  13. }

  14. return 0;

  15. }

    运行结果:

    简单说明一下:argc表示指针数组的个数,argv中每个指针对应着包括运行路径在内的参数字符串。我们明白了这两个参数的原理以后,一定不要放任不管了,其实所谓厉害的算法或者代码都是由一点一点的小技巧堆积起来的,所以这里我们在以后的相关项目对于普通函数也可以进行这样的传参方式,使得我们的参数更加的灵活。


2、结构体和共联体可直接赋值

    大家都知道C语言中的数组是不能够直接进行赋值操作的,那么我们大部分的小伙伴在学习数组的时候一定把循环语句练习得特别熟了,因为需要一个个赋值操作,那么我们可能潜意识的觉得,结构体或者是共联体这样的多种基础数据类型构成的数据类型应该也不能直接进行赋值操作,那我们下面敲一些代码试一试看看:

  1. #include <stdio.h>

  2. #include <stdlib.h>


  3. /************************************

  4. * Fuction:数据类型定义区域

  5. * Author :(公众号:最后一个bug)

  6. ***********************************/

  7. typedef struct _tag_sTest

  8. {

  9. int a;

  10. int b;

  11. int c;

  12. } sTest;


  13. typedef union _tag_uTest

  14. {

  15. int a;

  16. int b;

  17. int c;

  18. } uTest;

  19. /************************************

  20. * Fuction: main

  21. * Author :(公众号:最后一个bug)

  22. ***********************************/

  23. int main(int argc, char *argv[]) {

  24. //定义变量

  25. sTest stTest1;

  26. sTest stTest2;

  27. uTest unTest1;

  28. uTest unTest2;


  29. //对1进行复制

  30. stTest1.a = 1;

  31. stTest1.b = 2;

  32. stTest1.c = 3;


  33. unTest1.a = 4;


  34. //对结构体和共联体直接赋值

  35. stTest2 = stTest1;

  36. unTest2 = unTest1;


  37. //查看运行结果

  38. printf("stTest2.a = %d\n",stTest2.a);

  39. printf("stTest2.b = %d\n",stTest2.b);

  40. printf("stTest2.c = %d\n",stTest2.c);


  41. printf("unTest2.c = %d\n",unTest2.c);


  42. return 0;

  43. }

    编译通过,运行结果如下:

    解析一下:这样也就证明我们的结构体和共联体变量是能够直接进行赋值操作的,那一些小伙伴会想这样有什么好处吗?感觉和一个个赋值差不多吧,其实不然,直观的作用至少在结构体成员比较多的变量赋值操作可以省一大片代码,便于阅读,另外一个非常有用的就是可以作为函数直接传递参数和返回值了,下面我会再次提到这一点。

    不过我们需要注意一点的是,结构体直接的数值赋值仅仅只能够在初始化的时候进行整体赋值,而在其他位置是不允许直接数值块赋值,如stTest1 ={1,2,3};,不过可以进行上面例子那样变量赋值,这一点和数组是类似的。


3、函数返回值的问题

    大家在平时的编程中应该都知道,我们的函数都只能返回一个数值(地址也可以认为是一个特殊的数值),那么我们平时对于相关的函数可能就想实现能够传递出来多个数值,那么我们该如何处理呢?这里作者为大家总结了几种方案供大家参考:

    1)采用结构体的方式,也就是上一小节说的,这个个人感觉比较方便;

    2)用全局变量进行传递参数;

    3)用指针进行参数传入,一般就不需要再返回数据了,同时一定要注意不能返回局部变量的地址,因为函数运行结束局部变量就会被释放.


4、今日小结

    今天讲的这几个小例子,其实主要是想告诉大家要敢于去尝试去思考一些常规性的问题,然后从中获得一些有用的知识技能,作为一名程序员我觉得思考归纳抽象能力在一定程度上决定了代码的质量。

    好了,今天就说这么多了,感谢大家的关注和支持,希望大家都能攻克bug,早点下班,这里是公众号:"最后一个bug",下期再见!

推荐好文  点击蓝色字体即可跳转

【系列】嵌入式编程"进阶有道”--C语言篇(1)

嵌入式编程之"重构"代码(C语言版本) 

单片机常用程序框架之分时轮询(详注代码) 

【连载】通过"库文件"学单片机驱动编程(5)-完结篇

C语言为什么一般不在.h中定义函数或者变量?(精华)

手把手教你写Modbus-RTU协议(理论篇)

单片机开发之节省内存大法(C语言版本)

嵌入式编程之动态接口技术(经验干货)

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存