发新帖我要提问
12
返回列表
打印
[电路设计]

C++还是C欢迎灌水拍砖 (灌水榜20名 一人一份)

[复制链接]
楼主: kyzb001
手机看帖
扫描二维码
随时随地手机跟帖
21
john_lee| | 2011-12-16 12:58 | 只看该作者 回帖奖励 |倒序浏览
楼上说的确实是实情。但也不是说没有师傅就学不好c++,只不过相对来说难度大些,时间长些。

使用特权

评论回复
22
kyzb001|  楼主 | 2011-12-16 13:43 | 只看该作者
手头上 有二本书~
一本是C++ primer
一本是C和指针.
:D

使用特权

评论回复
23
乡村男孩| | 2011-12-16 13:47 | 只看该作者
到目前为止没用用过C++,所以还不能真正知道面向对象和面向过程的真正区别,但是C++的一些机制还是很不错,用C实现的东西到后面来发现如果会C++,那样写出来更加能让程序结构紧凑和完整;

使用特权

评论回复
24
kyzb001|  楼主 | 2011-12-16 16:20 | 只看该作者
我是c++高手...

如果没有师傅带,用c++写和c没什么优势,因为你不知道如何写才有优势
icecut 发表于 2011-12-16 12:53
这师傅上哪里找去哇!!!

使用特权

评论回复
25
john_lee| | 2011-12-17 01:50 | 只看该作者
本帖最后由 john_lee 于 2011-12-17 02:00 编辑

嗯,不错,各有各的观点,欢迎讨论。

在大程序中,使用C++是有优势的,这一点貌似大家都认同。

那我们就往程序的细节方向讨论,看看C++是否还有优势。

在单片机中,特殊功能寄存器(SFR, Special Function Register)的访问可谓是非常细节了,我们知道,RISC架构的CPU,程序要修改一个SFR中的某一个或某几个特殊功能位域(SFBF, Special Function Bit Field)时,需要将整个SFR读到CPU寄存器中,在CPU寄存器中修改完毕后,再写回到SFR,这就是所谓的“读-修改-写”过程。

那么,使用C语言应该如何来描述这个操作?
一般有两种方法:
1、位操作(与,或,反,异或)
例如:对SFR中的bit2, bit5置1,一般的写法大致如下:
#define SFB_LED 0x04 // 或(1 << 2)
#define SFB_RELAY 0x20 // 或(1 << 5)
SFR |= SFB_LED | SFB_RELAY;
可以看出,位操作是以整个SFR为目标的赋值操作,表达式右值就是SFR,编译器生成的代码会先“读”,然后“修改”所有需要修改的位,最后“写”,所以代码效率是最高的,这是位操作的优点。但是,SFB_LED, SFB_RELAY等宏代表的SFBF,与SFR在语法逻辑上没有任何关系,编译器不可能知道这些SFB_LED, SFB_RELAY是属于这个SFR的,如果你错写成了另外的宏(数值定义),编译照样通过。这个属于安全性问题。至于算不算缺点,那就要看有没有其它方法,使编译器可以检查SFR和SFBF的关系。如果没有,那么位操作就是目前最好的方法了;否则,安全性差就是位操作的缺点。

幸运的是,有方法,那就是位域。

2、位域
我们还是以上面的例子,但是用位域的方式实现:
struct sfr {
    uint32_t : 2;
    volatile uint32_t SFB_LED : 1;
    uint32_t : 2;
    volatile uint32_t SFB_RELAY : 1;
};
extern struct sfr SFR;
SFR.SFB_LED = 1;
SFR.SFB_RELAY = 1;
使用位域的方式来定义SFBF,利用了语言本身的作用域的约束检查,编译器可以明确地知道SFB_LED,SFB_RELAY是属于SFR的,当你写错时,编译器一定不会任你错下去,这正好克服了位操作安全性差的缺点。

但是,我们还注意到了,位域的操作,不再是以整个SFR为目标了,而是以其中的某个位域为目标,而位域的定义,由于是SFBF,为了保证操作的确定性以及防止优化,所以,一般需要加上volatile修饰,这样的结果是,程序每修改一个SFBF,编译器就会生成一个“读-修改-写”的过程。

如果我们的程序修改了同一个SFR中的两个SFBF,按刚才的规则,编译器将会生成两个“读-修改-写”,但我们可能不需要这两个SFBF有一定的先后顺序(甚至需要两个SFBF同时操作),而希望编译器把两个“读-修改-写”合并为一个。但是我们失望了。

现在,我们来做个小结:
SFBF操作方式: 位操作 位域
效率:
安全性:








看来,鱼和熊掌,不可兼得啊。

接下来,试试C++。

我们定义了一堆类,模板,重载操作符等等(实现细节就省了,否则两屏幕都写不完)。

展示一下用法:
                                 // 等效的C表达式为:
SFR().SFB_LED(1).SFB_RELAY(1);   // SFR |= SFB_LED | SFB_RELAY;
SFR().SFB_LED(0).SFB_RELAY(0);   // SFR &= ~(SFB_LED | SFB_RELAY);
SFR().SFB_RELAY(0).SFB_LED(1);   // SFR = (SFR | SFB_LED) & ~SFB_RELAY;
SFR(0).SFB_LED(1);               // SFR = SFB_LED;
SFR(~0).SFB_LED(0);              // SFR = ~SFB_LED;
SFR(0);                          // SFR = 0;
如果嫌可读性不好,那么可以这样:
SFR()
    .SFB_LED(1)
    .SFB_RELAY(1);
C++的SFR访问方法,不仅安全性同位域一样有保证,效率也同位操作一样高效,并且写法也很优雅。

总结了:
SFBF操作方式: C位操作 C位域 C++
效率:
安全性:

使用特权

评论回复
26
kyzb001|  楼主 | 2011-12-17 10:08 | 只看该作者
:victory:  犀利!

使用特权

评论回复
27
weshiluwei6| | 2011-12-18 14:01 | 只看该作者
菜鸟飞啊非啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则