百科问答小站 logo
百科问答小站 font logo



为什么招聘单片机工程师的时候要求精通C/C++? 第1页

  

user avatar   zhang-hao-72 网友的相关建议: 
      

8位mcu上基本不会用到c++,随便写点啥,那点flash/ram就满了。(51不知道,avr的话,g++是可以用的,有没有人用是另一回事。)32位mcu经常都是上百k的flash和几十k的ram了,想用c++的话是可以用的。

不过更关键的还是面向对象的思维方式吧。

举个简单的例子,要用个i2c外设,这个好办,不管是硬件i2c还是软件i2c,就那么几个操作,随便写写就行了。

但是如果同时要用好几个i2c外设呢?只是管脚不同,把同样的代码复制粘贴几份吗?那就太傻了吧。

i2c无非是start, stop, ack, nack, waitack, read/write这么几个操作,把它们抽象出来作为一个i2c对象,需要用到的管脚作为参数传进去,然后把对象的指针交给外设驱动程序,外设驱动里再调用前面几个操作的函数指针,这样层次上就清晰多了。

上代码,先建立一个i2c对象类型:

       typedef struct i2cobj {     GPIO_TypeDef* gpiox;     GPIO_Pin_TypeDef sda, scl;     void (*start_f)();     void (*stop_f)();     void (*ack_f)();     void (*nack_f)();     void (*waitack_f)();     unsigned char (*readwrite_f)(unsigned char); } i2cobj_t;     

具体实现就不用写了吧,都差不多。用到的时候先建个i2cobj_t的实例,把用到的管脚作为参数传进来,执行相应的初始化,再把实例的指针传给具体的外设驱动。

           i2cobj_t i2c;     i2c.gpiox = GPIOB;     i2c.scl = GPIO_Pin_8;     i2c.sda = GPIO_Pin_9;     SOFTI2C_Config(&i2c);     OPT3001_Init(&i2c);     

外设驱动里回调start_f, stop_f等函数指针,这样再多用几个i2c,都不成问题。想用软件i2c也行,用硬件i2c也行,只要修改i2c对象的实现,具体外设的驱动不用动。是不是很美妙?

然而这里有一个很大的问题:c的函数是全局的,外设驱动里调用i2c->start_f时,start_f函数里没法知道应该操作哪个i2c对象的sda和scl管脚。解决办法只能是在每个函数指针增加一个参数,把i2c对象的指针传进来,前面的类型实际上应该写成这样:

       typedef struct i2cobj {     GPIO_TypeDef* gpiox;     GPIO_Pin_TypeDef sda, scl;     void (*start_f)(struct i2cobj* obj);     void (*stop_f)(struct i2cobj* obj);     void (*ack_f)(struct i2cobj* obj);     void (*nack_f)(struct i2cobj* obj);     void (*waitack_f)(struct i2cobj* obj);     unsigned char (*readwrite_f)(struct i2cobj* obj, unsigned char); } i2cobj_t;     

然后外设驱动里是这样调用的:

       static i2cobj_t g; void OPT3001_Init(i2cobj_t* obj) {     g = *obj;   // 这里仍然有坑,使用多个同型号外设时,需要用类似的思路,把外设对象化、建立多个实例来操作,这里省略     具体外设初始化操作; }  static unsigned short ReadReg(unsigned char reg) {     unsigned short val;     g.start_f(&g);                 // 每个i2c基本操作都要带上&g     g.readwrite_f(&g, CMD_WRITE);     g.waitack_f(&g);     g.readwrite_f(&g, reg);     g.waitack_f(&g);     g.start_f(&g);     g.readwrite_f(&g, CMD_READ);     g.waitack_f(&g);     val = g.readwrite_f(&g, 0xff);     g.ack_f(&g);     val <<= 8;     val |= g.readwrite_f(&g, 0xff);     g.nack_f(&g);     g.stop_f(&g);     return val; }     

如此,问题解决了,多个i2c外设工作得很好,只是这个写法实在是蛋疼。

如果是c++呢?以上问题自然就简单得多了,c++对象的this指针就是干这个的。

c++自然又有c++的一系列问题,就不多说了。

---------------------------更新--------------------------------

把我的i2c库开源了, 安利一下, Github链接:


user avatar   kuang-qi-84 网友的相关建议: 
      

所谓的大部分单片机项目不用C++是因为整个嵌入式开发行业从业者的平均软件素养已经差到了一个令人发指的地步。

大部分嵌入式工程师出身于电子、通信、自动化等专业,由于专业教育的缺失和自己学习能力的问题,根本不具有面向对象设计、设计模式、软件工程等基本常识,所以在他们看来C和C++差不多,没必要上C++。

一个基层工程师,整天满嘴都是稳定、可靠、市场、成本、性价比这些屁话,却根本没听说过设计模式、代码复用、可扩展性、单元测试、持续集成这些现代软件技术的精华。知道的知道你是一个强行挽尊的嵌入式工程师,不知道的还以为你是什么统领千军的大老板。

(我预判了他们的预判,这段真的戳到了一些传统的嵌入式工程师。居然有人跟我杠说设计模式、单元测试、持续集成这些不重要?我通篇就是打的这样人的脸,你被打完了还跟我说:你打脸而已,没打到要害,你根本就不会打人!我笑得满地打滚!)

所有没用到C++的单片机应用项目(底层驱动库不在此列),都是因为其规模过小,应用过于简单,一两个人,最多不超过5人就可以完成全部开发,这种项目不但用不到C++,甚至用不到C,甚至用汇编完成,更用不到任何现代软件工程技术。作为一个嵌入式开发的候选人,如果你想加入大厂,参与任何有规模的嵌入式项目,你的C++水平就是你的天花板。这里的大厂不止是华为、大疆这种,甚至很多爱好者熟悉的“周立功单片机”老板周立功就多次在公开场合表示,他们已经全面转向C++,只会C的工程师不会得到工作机会。

Arduino也许是世界上最著名的AVR(8位单片机)项目,没有之一。Arduino的封装全面使用了C++和面向对象的设计。广泛使用基于虚函数实现的运行时多态,很多设计遵从了开闭原则、接口隔离、依赖倒置等重要设计原则。我曾经详细分析过一个依赖倒置的使用案例,请见:

Arduino 的 Serial.write() 和 Serial.print() 的区别在哪里? - Qi K的回答 - 知乎 zhihu.com/question/2130

在ARM项目中, 用到C++的更多。ARM官方推动的mbed项目大概是ARM单片机领域最知名的项目之一。如果你要抬杠说Arduino是玩具,不具有工业强度的话,那mbed项目绝对是为工业级应用设计的,从底层RTOS到上层的硬件抽象层HAL都有实现。mbed是用C++实现的,广泛使用开闭原则和依赖倒置,要求用户通过继承虚基类来完成平台相关的实现,从而实现扩展。

如果你是一个一线嵌入式工程师,却根本不了解我提到的一些专业术语是什么意思,我觉得应该反思一下为什么自己的工资上不去。因为这些都是最基础的面向对象和设计模式常识。

最后回答问题,为什么单片机工程师要求会C++?那还不简单?因为企业不傻啊!


P.S. 有朋友提到C++的程序占用空间大,我只能说你姿势不对,C++的demangling、RTTI、Exception等机制确实会占用一些额外的Flash空间,但这不是不用C++的理由,在空间要求严格的项目中这些feature都可以通过编译器选项关掉,实际空间占用与纯C相比并无明显差别。


特别喜欢跟网友抬杠,所以欢迎留言~但如果你想批评我的某些观点,而你却没有开发过单个固件超过10万行代码、单个代码库活跃的协同开发人数大于5人的单片机项目,那你很可能因认知水平与我差距过大而无法理解我说的什么。你可以安全地假设你的观点是错误的,并尝试接受新的观点。


有些评论有点跑偏了哈~其实我也是C的铁粉,C在嵌入式领域毫无疑问占有举足轻重的地位。这篇文章的主题并不是证明C语言垃圾,应该用C++替代,试图证明一种语言应该替代另外一种语言的尝试都是愚蠢而无意义的。我坚定认为在现代嵌入式系统中,C和C++共存的现象会广泛存在,且具有上升的趋势。在硬件抽象层使用C,在应用层和接口层使用C++是非常典型的实践。这也是正面回答这个问题,为什么嵌入式要会C++?因为嵌入式应用中C和C++都有用。

说了这么多,如果你的观点还是“C++无用,C++滚出嵌入式”的话,祝你好运!




  

相关话题

  对容器类做改变的设计是否存在天生的错误? 
  C/C++有什么库可以完成命令行参数解析? 
  C++过于复杂为什么不被淘汰? 
  fopen()的第二个参数为什么会采用字符串形式? 
  为什么IT书籍的翻译质量相比其他尤其被诟病? 
  你有过哪些被 C++ 摧残的经历? 
  C++中 int n = 0ULL - 1; 是 UB 未定义行为吗? 
  C/C++语言指针究竟难在哪里? 
  为什么招聘单片机工程师的时候要求精通C/C++? 
  8051 6502 avr的好处都有啥? 

前一个讨论
不懂就问:一根粗导线与一根细导线串联对接,粗导线的电子会把细导线挤爆吗?知道不会,可为什么不会?
下一个讨论
馒头放在空气里会变硬,而饼干放在空气里变软,是什么原因呢?





© 2024-06-26 - tinynew.org. All Rights Reserved.
© 2024-06-26 - tinynew.org. 保留所有权利