MDK中使用C++的发现
·对象:MDK安装目录中的c++ 例程C:\Keil\ARM\Examples\C++\Example1
·问题:例程中如何将标准输入cin、输出cout对象与硬件串口映射起来的?
·发现:首先,main()前有一段说明
上面说的是Serial.c里面的$Sub$$__rt_entry()做了串口初始化的工作,先不管是不是它说的那样,看main里面并没有做串口的任何操作就能使用cin和cout将数据从串口读入和写出。肯定是main进入之前就将他们之间的映射做好了,回过头来看Serial.c代码,里面有一处比较特别的地方:
/*----------------------------------------------------------------------------
Superclass to initialize the serial interface
*----------------------------------------------------------------------------*/
extern void$Super$$__rt_entry(void);
void$Sub$$__rt_entry(void) {
SER_Init();
$Super$$__rt_entry();
}
这些奇怪的东西是怎么调用的?我们看下程序充零开始执行的过程:
(注:图片来源ARM官网)
(注:图片来源网络)
__main是用来设置内存,__rt_entry是用来设置运行时环境(设置堆栈、初始化库函数、静态数据和调用顶层C++构造器)然后才进入用户的main代码,用户main执行完后__rt_entry还会去关掉库等。
好吧,那上面的代码又是如何做到在main前就做串口初始化的工作的呢?
额,利用 $Sub
和 $Super
函数包装符可以插入一个紧接主应用程序之前执行的例程。 这一机制使您能在不改变源代码的情况下扩展函数。(厉害。。。)
· 使用 $Super$$ 和 $Sub$$ 覆盖符号定义
在某些情况下,无法修改现有符号,例如,由于符号位于外部库或 ROM 代码中。
可以使用 $Super$$ 和 $Sub$$ 模式来修补现有符号。
例如,要修补函数 foo() 的定义,请按如下方式使用 $Super$$foo() 和 $Sub$$foo():
$Super$$foo
标识未修补的原始函数 foo()。 使用它可以直接调用原函数。
$Sub$$foo
标识调用的新函数,而不是原始函数 foo()。 可以使用此模式在原始函数之前或之后添加处理。
Note
$Sub 和 $Super 机制只在静态链接时起作用,$Super$$ 引用无法导入或导出到动态符号表中。
Example 4.4 说明修改遗留函数 foo() 而导致调用 ExtraFunc() 和 foo()。 有关详细信息,请参阅《ARM 体系结构的 ELF》。
Example 4.4. 使用 $Super$$ 和 $Sub$$
extern void ExtraFunc(void);
extern void $Super$$foo(void):
/* this function is called instead of the original foo() */
void $Sub$$foo(void)
{
ExtraFunc(); /* does some extra setup work */
$Super$$foo(); /* calls the original foo() function */
}
所有说是用这两个东东修补了__rt_entry的定义了哦(其实是添加了),明显就是标示了新的__rt_entry添加了自己要初始化的部分后又调用了原来的entry嘛。
其他的代码应该简单了哈。