不知有没有人对C++开发STM32感兴趣的,来讨论些问题
3个回答
推荐于2017-11-27 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
向TA提问 私信TA
知道合伙人数码行家
采纳数:117538
获赞数:517177
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。
向TA提问 私信TA
关注
展开全部
因为一开始我自学的就是C++,后来玩单片机以后才使用C语言来开发东西,也写过一些程序了,
但是我的体会就是,C语言没有C++那么方便,最近才在学STM32,看到ARM编译器能够支持C++,挺爽的,就开始尝试把实验代码的工程改成C++的方式
出现了一些问题,我不太会查资料,网上讨论这个的也比较少,所以就发个帖子大家一起讨论下
先说一下,为什么要用C++,(说的可能不太清楚,对没学过C++的哥们就不好意思啊呃。。。)
1. 最简单的,函数重载, 这个语法特性就比C语言的好,还有运算符重载,这些都可以让代码变得更直观(这个等下我用我刚刚拓展的代码来演示一下)
2. 命名空间,C语言写大程序一般每个模块都会有个前缀,但是写起来麻烦,其实有时候在一个地方只会用到一个模块的内容,所以用using xxx::xxx感觉会比较方便些。
3. 类的支持,尤其是成员函数什么的使用起来方便,还有constructor,不用每次手动调用初始化。
(关于这个还是有一点问题我没有解决的,好像是全部类变量的初始化问题,我比较健忘,记不清了)
4.inline关键字,可以解决宏的一些缺陷 (有热心网友指出,用C也有__inline关键字)
5.引用参数的支持,比直接使用指针省事放心些
6.模板的支持,(这个在我之前发过的一个关于宏的帖子里有提到一点,也有提供代码,这个帖子的附件里面也有代码)
7.至少,网上说的,C++具有C的全部优点
关于我上面说的优点,也有网友对我的观点不屑,
有的说C++效率低下(关于这个我并不理解,因为我反汇编看过,没有明显的区别,除非你使用了继承多态的特性可能会有问题,
但是,在有些地方就需要使用这些特性,特别是在比较大的系统里,比如GUI,就算是用C语言去模拟面象对象的实现过程效率也是差不多的)
还有网友称C++的一些语法特性为语法糖,没多大用处(呵呵,这个就看个人喜好了,就像学过汇编的哥们可能就喜欢写汇编,不喜欢用C语言一样)
我也不打算说服所有的人,我只是希望有兴趣的人能和我一起交流意见,我之前发了那个帖子之后,就有一位华工刚毕业的师兄感兴趣,通过邮件和我交流
只可惜那个时候我一直没什么时间继续解决那些问题。趁这个下午有点时间,我就改了一下之前的代码,再到这里发帖,希望有兴趣的人能一起交流。
下面是我遇到的一些问题,有的已经解决,有的还没解决:
1. 以前的库函数怎么使用?
在函数声明前加上 extern "C" 就可以了,因为C++支持函数重载之类的东东,所以生成的目标代码的名字和C会有些不同,用extern "C"强制成C语言的名字规则。
现在新版本的库好像已经加上了,这里顺便问一下,新版本的库在官网的哪里下载?我不要一点就直接弹出下载的链接
新版的STM32的库的头文件前面是
#ifdef __cplusplus
extern "C" {
#endif
后面
#ifdef __cplusplus
}
#endif
这就是为了兼容C++的。
2. 中断函数进不去呀?
中断函数定义前也要加上 extern "C"。中断函数,名字已经固定了(在你使用MDK给的启动代码的情况下),
而C++对函数的生成的目标代码的命名方式和C语言不一样(为了支持重载),
然后我是以这种方式来解决的,
#define ARMAPI extern "C"
ARMAPI void EXTI15_10_IRQHandler(void)
{
...
}
3. 对库里面定义的结构体有警告: warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
这个没有关系的,我用这段代码屏蔽了中间警告
#ifdef __cplusplus
extern "C" {
//消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#pragma diag_remark 368
#endif
...
...
#ifdef __cplusplus
//恢复368号警告
#pragma diag_default 368
}
4. C++有 new 关键字,类似C的malloc,但是这个是需要有内存管理提供动态内存的,这个在一个没有操作系统的MCU上咋整呀?
其实关于使用C++的,国外已经有成功的例子了(只是IDE用的不是MDK。。。),我从网友提供的链接去下载了源代码:
http://andybrown.me.uk/ws/2011/12/28/stm32plus-a-c-library-for-stm32-development/
(PS:看了他们的代码库,我发现我以前写的文件系统实在是弱啊。。。没关系,会继续完善的)
人家是这么搞的,利用函数重载,重载了new操作符,(软件仿真会跳进重载的函数里)
,自己只要提供malloc和free以及堆的一些初始化就行了(这个一般要上了OS才有内存管理的吧。。。)
/* * Implement C++ new/delete operators using the heap */
void *operator new(size_t size)
{ return malloc(size); }
void *operator new[](size_t size)
{ return malloc(size); }
void operator delete(void *p)
{ free(p); }
void operator delete[](void *p)
{ free(p); }
还有些没解决的问题
5. 定义全局类变量后会有错误:
..\output\stm32test.axf: Error: L6218E: Undefined symbol __cpp_initialize__aeabi_ (referred from anon$$obj.o).
class A
{
public :
A()
{
int x, y;
x = 5;
y = 7;
x = y;
y = x + 8;
}
};
A a;
有些地方可能不清楚,原帖子在这个链接:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5401612&bbs_page_no=1&search_mode=3&search_text=Pony279&bbs_id=9999
然后是我刚刚做的设置IO口模式的几个函数的测试代码,因为实现代码比较长,我不会帖上来,
在附件里面有完整的代码,测试代码在gpio_test_120309a.cpp文件里,相关的代码全部在 MYLIB文件夹里面也有。
(自己在学习的时候整理的函数都在那里面,其实内容比较少。。。)
我这里只是为了演示使用的便利性的提高和代码的阅读性的提高。
SetMode函数实现是利用了函数重载的,和默认参数。如果不知道什么是重载的,先不要去想语法,直接看代码,看得懂不?
int main(void)
{
{using namespace gpio; //在这个代码block里面使用gpio的命名空间。
SetMode(GPIOA, Pin(0), OUTPUT); //设置PA0为输出模式,有默认参数 开漏输出, 这里没有写出来
SetMode(GPIOA, Pin(1), OUTPUT, OPEN_DRAIN, _50M);
SetMode(GPIOA, Pin(2), OUTPUT, PUSH_PULL, _50M);
SetMode(GPIOA, Pin(3), INPUT); //有默认参数,上拉输入,没有写出来。
SetMode(GPIOA, Pin(8), INPUT, PULL, DOWN);
SetMode(GPIOB, Pin(3), INPUT);
SetMode(GPIOB, Pin(8), INPUT, PULL, DOWN);
}
//仿真结果和预期一致。
while(1);
}
函数重载是语法上允许同名函数的存在,但是需要这两个函数的参数列表是不同的,使用的时候,编译器会知道你要调用的是哪个函数。
在写代码的时候对于一个同样功能但是参数类型不同的函数,如果需要起不同的名字,不论是写代码还是读代码都会比较痛苦的,
我上面好像提了几次代码的阅读性的问题,因为我一直很重视代码的阅读性,这一点从我之前发的那个关于宏的帖子大家也可以知道。
因为,我想老鸟应该有体会,其实程序猿花在读代码上的时间,是远大于写代码的时间的。
好像扯远了。。。就先到这里吧。。。
但是我的体会就是,C语言没有C++那么方便,最近才在学STM32,看到ARM编译器能够支持C++,挺爽的,就开始尝试把实验代码的工程改成C++的方式
出现了一些问题,我不太会查资料,网上讨论这个的也比较少,所以就发个帖子大家一起讨论下
先说一下,为什么要用C++,(说的可能不太清楚,对没学过C++的哥们就不好意思啊呃。。。)
1. 最简单的,函数重载, 这个语法特性就比C语言的好,还有运算符重载,这些都可以让代码变得更直观(这个等下我用我刚刚拓展的代码来演示一下)
2. 命名空间,C语言写大程序一般每个模块都会有个前缀,但是写起来麻烦,其实有时候在一个地方只会用到一个模块的内容,所以用using xxx::xxx感觉会比较方便些。
3. 类的支持,尤其是成员函数什么的使用起来方便,还有constructor,不用每次手动调用初始化。
(关于这个还是有一点问题我没有解决的,好像是全部类变量的初始化问题,我比较健忘,记不清了)
4.inline关键字,可以解决宏的一些缺陷 (有热心网友指出,用C也有__inline关键字)
5.引用参数的支持,比直接使用指针省事放心些
6.模板的支持,(这个在我之前发过的一个关于宏的帖子里有提到一点,也有提供代码,这个帖子的附件里面也有代码)
7.至少,网上说的,C++具有C的全部优点
关于我上面说的优点,也有网友对我的观点不屑,
有的说C++效率低下(关于这个我并不理解,因为我反汇编看过,没有明显的区别,除非你使用了继承多态的特性可能会有问题,
但是,在有些地方就需要使用这些特性,特别是在比较大的系统里,比如GUI,就算是用C语言去模拟面象对象的实现过程效率也是差不多的)
还有网友称C++的一些语法特性为语法糖,没多大用处(呵呵,这个就看个人喜好了,就像学过汇编的哥们可能就喜欢写汇编,不喜欢用C语言一样)
我也不打算说服所有的人,我只是希望有兴趣的人能和我一起交流意见,我之前发了那个帖子之后,就有一位华工刚毕业的师兄感兴趣,通过邮件和我交流
只可惜那个时候我一直没什么时间继续解决那些问题。趁这个下午有点时间,我就改了一下之前的代码,再到这里发帖,希望有兴趣的人能一起交流。
下面是我遇到的一些问题,有的已经解决,有的还没解决:
1. 以前的库函数怎么使用?
在函数声明前加上 extern "C" 就可以了,因为C++支持函数重载之类的东东,所以生成的目标代码的名字和C会有些不同,用extern "C"强制成C语言的名字规则。
现在新版本的库好像已经加上了,这里顺便问一下,新版本的库在官网的哪里下载?我不要一点就直接弹出下载的链接
新版的STM32的库的头文件前面是
#ifdef __cplusplus
extern "C" {
#endif
后面
#ifdef __cplusplus
}
#endif
这就是为了兼容C++的。
2. 中断函数进不去呀?
中断函数定义前也要加上 extern "C"。中断函数,名字已经固定了(在你使用MDK给的启动代码的情况下),
而C++对函数的生成的目标代码的命名方式和C语言不一样(为了支持重载),
然后我是以这种方式来解决的,
#define ARMAPI extern "C"
ARMAPI void EXTI15_10_IRQHandler(void)
{
...
}
3. 对库里面定义的结构体有警告: warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
这个没有关系的,我用这段代码屏蔽了中间警告
#ifdef __cplusplus
extern "C" {
//消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#pragma diag_remark 368
#endif
...
...
#ifdef __cplusplus
//恢复368号警告
#pragma diag_default 368
}
4. C++有 new 关键字,类似C的malloc,但是这个是需要有内存管理提供动态内存的,这个在一个没有操作系统的MCU上咋整呀?
其实关于使用C++的,国外已经有成功的例子了(只是IDE用的不是MDK。。。),我从网友提供的链接去下载了源代码:
http://andybrown.me.uk/ws/2011/12/28/stm32plus-a-c-library-for-stm32-development/
(PS:看了他们的代码库,我发现我以前写的文件系统实在是弱啊。。。没关系,会继续完善的)
人家是这么搞的,利用函数重载,重载了new操作符,(软件仿真会跳进重载的函数里)
,自己只要提供malloc和free以及堆的一些初始化就行了(这个一般要上了OS才有内存管理的吧。。。)
/* * Implement C++ new/delete operators using the heap */
void *operator new(size_t size)
{ return malloc(size); }
void *operator new[](size_t size)
{ return malloc(size); }
void operator delete(void *p)
{ free(p); }
void operator delete[](void *p)
{ free(p); }
还有些没解决的问题
5. 定义全局类变量后会有错误:
..\output\stm32test.axf: Error: L6218E: Undefined symbol __cpp_initialize__aeabi_ (referred from anon$$obj.o).
class A
{
public :
A()
{
int x, y;
x = 5;
y = 7;
x = y;
y = x + 8;
}
};
A a;
有些地方可能不清楚,原帖子在这个链接:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5401612&bbs_page_no=1&search_mode=3&search_text=Pony279&bbs_id=9999
然后是我刚刚做的设置IO口模式的几个函数的测试代码,因为实现代码比较长,我不会帖上来,
在附件里面有完整的代码,测试代码在gpio_test_120309a.cpp文件里,相关的代码全部在 MYLIB文件夹里面也有。
(自己在学习的时候整理的函数都在那里面,其实内容比较少。。。)
我这里只是为了演示使用的便利性的提高和代码的阅读性的提高。
SetMode函数实现是利用了函数重载的,和默认参数。如果不知道什么是重载的,先不要去想语法,直接看代码,看得懂不?
int main(void)
{
{using namespace gpio; //在这个代码block里面使用gpio的命名空间。
SetMode(GPIOA, Pin(0), OUTPUT); //设置PA0为输出模式,有默认参数 开漏输出, 这里没有写出来
SetMode(GPIOA, Pin(1), OUTPUT, OPEN_DRAIN, _50M);
SetMode(GPIOA, Pin(2), OUTPUT, PUSH_PULL, _50M);
SetMode(GPIOA, Pin(3), INPUT); //有默认参数,上拉输入,没有写出来。
SetMode(GPIOA, Pin(8), INPUT, PULL, DOWN);
SetMode(GPIOB, Pin(3), INPUT);
SetMode(GPIOB, Pin(8), INPUT, PULL, DOWN);
}
//仿真结果和预期一致。
while(1);
}
函数重载是语法上允许同名函数的存在,但是需要这两个函数的参数列表是不同的,使用的时候,编译器会知道你要调用的是哪个函数。
在写代码的时候对于一个同样功能但是参数类型不同的函数,如果需要起不同的名字,不论是写代码还是读代码都会比较痛苦的,
我上面好像提了几次代码的阅读性的问题,因为我一直很重视代码的阅读性,这一点从我之前发的那个关于宏的帖子大家也可以知道。
因为,我想老鸟应该有体会,其实程序猿花在读代码上的时间,是远大于写代码的时间的。
好像扯远了。。。就先到这里吧。。。
意法半导体(中国)投资有限公司
2023-06-12 广告
2023-06-12 广告
STM32是一种32位的微控制器,由意法半导体(STMicroelectronics)公司设计和生产。STM32是一种非常常见的嵌入式系统芯片,广泛应用于物联网、汽车、工业控制、医疗设备等领域。STM32具有以下特点:1. 体积小巧:STM...
点击进入详情页
本回答由意法半导体(中国)投资有限公司提供
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询
广告 您可能关注的内容 |