综合资讯 技术文章 原文阅读 在线商城 下载专区 DATASHEET 技术论坛 商务频道

电子技术 | 技术资料 | 嵌入式系统 | 单片机专题 | DSP专题
EDA/PLD专题 | 电源技术专题 | 电子制作专题 | 其他综合 | 芯片选型

所在的位置:首页在线阅读嵌入式系统VxWorks专辑正文
 
在嵌入式系统中使用ZINC

前一段时间使用ZINC,也在论坛里问了问题,但是回答的人不多......所以我将自己的学习笔记做了一些整理,贴出来与大家共享。疏漏之处在所难免,欢迎大家指正。

在嵌入式系统中使用ZINC

1 绪论
本文讨论在一个实时环境下的Zinc应用程序――Zinc on VxWorks的行为。运行在一个RTOS 上的应用程序通常有严格的实时需求,必须是可靠的,并且在某种程度上是确定的。
Zinc 框架既适用于桌面,也适用于RTOS,但当开发者针对一个RTOS 环境编码时,他要知道其中的重大的区别。
本文讨论在一个RTOS环境里对Zinc 特殊的问题:
o 嵌入式系统上的应用程序行为
o 多任务
o 多任务环境里的任务间通信
o 性能改进
o 在一个RTOS 目标机上存储Designer文件
o 实时问题的其它各个方面
本文假定你熟悉基本的Zinc操作。你应该知道事件(用户事件或应用程序事件)是如何进入系统的,它们如何被发送给正确的对象,以及对象如何处理它们。你还要熟悉事件管理器、窗口管理器、设备和主要的事件循环(ZafApplication::Control( ))。如果你对这些话题还不适应,请先去看《Zinc的体系结构》。

2 Zinc和嵌入式系统
Zinc for RTOS 与 Zinc for desktop 在下列行为和实现方面不一致:
o 应用程序入口点
o 输入队列任务
o 事件阻塞
o 事件队列保护
o ZafDisplay访问

2.1 应用程序入口点
在一个桌面应用程序里,入口点一般由编程语言或操作系统定义。对于编程语言C 和 C++,应用程序入口点是函数main( )。在Windows 操作系统里,入口点是函数WinMain( )。

注意:不要搞乱应用程序入口函数和ZafApplication::Main( ) 函数。它们是有不同目的的不同函数。

在一个RTOS 应用程序里,应用程序入口函数被调用来运行应用程序。ZafApplication::Main( ) 函数是应用程序的Zinc部分典型地将要开始的地方。

当你在一个桌面应用程序里使用Zinc时,应用程序入口函数是Zinc库的一部分――你不用去实现它。
在一个RTOS环境里,你必须自己写应用程序的入口点。有如下两个原因:
o 适应动态链接环境
在VxWorks里,可以想象Zinc库会被放置在目标机上面,单独的应用程序稍后下载。如果应用程序入口函数是在库里,它将设法调用一个共同的函数(例如ZafApplication::Main( )),而在这种情况下,该函数不存在 直到稍后应用程序被下载。这将在库被下载的时候返回一个错误:undefined symbol linker error
o 提供定制一个RTOS应用程序如何启动的能力
每个RTOS的应用程序都有不同的启动需要。一个RTOS应用程序可能需要在启动GUI任务之前产生若干任务或检测硬件。另外,它可能需要在GUI任务已经结束后产生一些任务。最容易的和最一致的处理一个嵌入式应用的独特需求的方法就是创建一个特殊的应用程序入口点。

创建ZafApplication实例
ZafApplication 类通常在应用程序入口函数处被实例化。
每个应用程序必须创建一个ZafApplication 类的实例。ZafApplication 类创建并维护对一个应用程序需要的对象(例如显示、设备、窗口管理器和事件管理器)的访问。(ZafApplication)对象 还设置全局变量 zafApplication ,用于获得对这些(对应用程序来说是全局的)对象的访问。
ZafApplication 还声明了一个成员函数Main( )。这个函数由开发者来写,并且通常是应用程序Zinc部分的开始之处。在桌面环境下, ZafApplication::Main( )是从库中的应用程序入口函数(main( ) or WinMain( ))处自动调用的。RTOS 应用程序入口函数调用ZafApplication::Main( )并非是严格要求的,但是我们建议这样做。参考任意一个Zinc demo目录中的文件v_app.cpp,作为一个例子。
修改 ZafApplication类的行为
如果需要,标准的ZafApplication 类的行为能够通过修改存在于文件z_app.cpp 中的构造函数来改变。要注意全局变量zafApplication 是作为一个任务变量创建的,因此, 在Zinc任务变成不活动和活动时,它被清除和恢复。分支问题以后在“3 多任务”中讨论。

2.2 事件取回—阻塞或非阻塞的事件取回
ZafApplication::Control( )函数在Zinc应用程序中是主要的控制环。它通过调用ZafEventManager::Get( ) 程序从事件管理器中获得事件,并继续发送这些事件到窗口管理器中,直到应用程序终止。当ZafEventManager::Get( )程序被调用时,其行为由传递给它的参数控制 。如果没有事件有效,程序可以立即返回,也可以阻塞直到事件变成有效。
如果程序因为没有事件可被处理而返回,将引起ZafApplication::Control( )程序处于一个忙等待情形,从而浪费不必要的CPU 时间。因此,在RTOS环境中,通常最好让ZafEventManager::Get( ) 阻塞直到事件变成有效。通过试图获取一个信号量使它阻塞。阻塞期由下列两种情况之一终止:
o 程序超时(这样做以便设备周期性地得到轮询)
o 阻塞信号量变成有效。当一个事件被放到队列中或者调用UnBlock( )明确地解除事件管理器的阻塞时,会发生这种情况。
这样,除非有频繁的事件,Zinc消耗许多的阻塞时间来等待信号量。

2.3 由信号量保护的事件管理器队列
信号量用于防止事件管理器队列每次被超过一个存取函数访问。这样,只要需要,调用EventManager::Get( ) 和EventManager::Put( )是安全的。由于这个保护,这些函数可能会阻塞,尽管可能性很小。

2.4 由信号量保护的 ZafDisplay访问
所有对display的访问应该不越出 ZafDisplay::BeginDraw( )和 EndDraw( ) 函数对。 这保证对display的受保护访问。
当你对一个窗口对象进行绘制时,由库为你执行下列任务:
o 信号量ZafScreenDisplay::classSem 被获取
o clip区域被设置
o 绘制被执行
o 信号量被释放
如果你直接对ZafDisplay进行绘制,你需要自己调用ZafDisplay::BeginDraw( )和 ZafDisplay::EndDraw( )。

3 多任务
大多数在一个实时环境中编写的应用程序是多任务的。几乎所有情况下, Zinc自身也是多
任务的。本节讨论Zinc在多任务情况下的使用。特别是:
o Zinc库的行为和需求
o Zinc应用程序的行为和需求

3.1 为什么使用多任务?
这儿有在一个应用程序中使用多任务的几个理由,最常见的原因是提高性能。对于在监控
环境下检测和响应错误状态来说,提高性能是非常紧要的;或者仅仅是想要创建平滑的动
画。
然而,你还能够使用多任务来分离应用程序的功能为不同的任务,从而简化源代码。

平衡GUI 和Non-GUI 任务性能
拥有GUI的嵌入式应用程序需要维持应用程序的GUI部分和实时部分的性能平衡。应用程序
必须在对用户输入保持响应的情况下,还能处理它计划要处理的无论什么样的实时或高优
先级的外部事件。这个平衡一般通过执行遵循下列指导方针的多任务应用程序来完成:
o 所有的GUI交互应该在Zinc任务中执行。多任务不应试图直接处理GUI 。使用
一个专用的GUI任务。
o 在分开的一个或多个任务中实现处理密集型或实时(或准实时)功能。
o GUI任务应该运转在一个足够低的优先级上,以便设计用来处理应用程序实时
方面问题的任务能够充分地做它们的工作。参见“任务优先级”。
o 通过在单独的任务中执行处理密集型的工作, GUI任务仍然能够保持对用户的
响应,因为它不用延时等待密集的处理结束。
Zinc提供与GUI任务交互的机制,因而外部任务能与GUI任务一起工作。交互的方法将在
“3.4 Zinc (GUI)任务和外部任务之间的通信方法”中进一步讨论。

3.2 Building Zinc成为可重入的
默认情况下,RTOS上的 Zinc 能够是多任务的,但不是可重入的。如果你需要Zinc成为可
重入的――例如,如果需要数个Zinc 应用程序同时运行――你可以build 一个可重入的
Zinc。
为了重入而build Zinc,需要在build Zinc库(关于build Zinc的详细资料参见 《从命令行配
置Zinc 》) 之前定义ZAF_REENTRANT宏。 Zinc 将使用许多信号量来保护共享数据。如
果保护共享数据对于应用程序来说并非必需,那就会引进不合乎需要的开销。
当build Zinc为重入时,大多数的窗口对象将使用一个叫做classSem 的静态成员。这是一
个ZafSemaphore ,用于对类的共享数据块的访问进行控制。你通常不需要直接访问这个
信号量,但是应该知道它。
如果不需要重入,不要定义ZAF_REENTRANT宏。默认情况下,该宏没有定义。

库关于重入的问题
Zinc库在带ZAF_REENTRANT 定义build时,几乎是完全可重入的。但有几个需要小心的地
方。
o 在某些函数里的Buffer 使用
有几个函数需要用明确的方式调用,以确保重入是安全的。这些函数列表如下:

表 1: 需要特别注意的函数

函数名

ZafCodeSetData::ConvertToOSString( )
ZafCodeSetData::ConvertToZafString( )
ZafCodeSetData::ConvertToOSWString( )
ZafCodeSetData::ConvertToZafWString( )
ZafConvertToOSString( )
ZafConvertToOSWString( )
ZafConvertToZafString( )
ZafConvertToZafWString( )

这些函数中的每一个都接受指向一个buffer 的指针作为一个变元。如果对此函数的调用没
有以一个buffer 的方式传递,该函数不是使用一个静态的内部buffer ,就是分配一个
buffer ,具体由另一个参数指示。

为了安全可重入,对这些函数的调用应该以一个buffer 的方式传递,或者要求函数分配一
个buffer。否则,这些函数将使用一个局部静态buffer 来包含数据,就有可能出现另一个
任务,在先前的调用结束使用此数据前,改变这些数据。所有Zinc内部的库对这些函数的
调用都是安全可重入的。

o strtok( ) 在Unicode模式不可重入
Zinc重载此函数以便在Unicode模式使用。库产生该函数的最小限度的使用(ZafFileDialog
是使用它的唯一对象),因而在一个可重入情形里小心使用此函数应该是安全的。

o ZafGetEnv( ) (getenv( ) 函数)是不可重入的
库仅仅在获取ZAF_LANG 和ZAF_PATH 环境变量时使用该函数,这发生在应用程序的开始
处。

o ZafI18nData::OSI18nName( ) 是不可重入的
o getcwd( )在Unicode模式不可重入

3.3 多任务应用程序
创建单独的任务的主要理由是从主GUI任务中尽可能地移开时间敏感的处理。这有保持GUI
和外部任务都响应的综合利益。
我们推荐你不要在外部任务里直接处理GUI ,而是在一个专用的GUI任务里执行所有的GUI
处理。作为这个分割的结果,外部任务将需要在不同的时期和GUI 任务通信,GUI也可能
需要与外部任务通信。本节主要介绍两种类型的通信方法。
在GUI任务和外部任务之间有两个主要的方法。方法的选择依赖于应用程序的需要:
o 异步通信,当外部任务在Zinc事件队列上放一个事件时使用ZafEventManager::Put( ) 方法。
由于是异步的,外部任务不用等待事件得到处理。
o 同步通信,当外部任务在做进一步工作之前调用
ZafApplication::BeginSynchronize( ) 函数时。
如果应用程序需要看见一些动作的结果或者需要以特殊的次序执行动作,这是有用的。在
调用BeginSychronize( )之后,外部任务可能直接发送事件给对象、更新对象数据等等。当
外部任务完成此工作,它必须调用函数ZafApplication::EndSynchronize( )。


注意: ZafEventManager::Put( )和ZafApplication::BeginSynchronize( ) 会阻塞,因此不
适于ISR级的使用或者任何阻塞无法接受的地方。

更多关于GUI任务和外部任务之间通信的细节,参见“3.4 Zinc (GUI) 任务和外部任务之间
的通信方式”。

全局的 Zinc 变量
全局变量应和共享数据一样小心对待。表2里的全局的Zinc变量都由信号量(每个都有一个
静态成员叫做classSem)保护:
表 2: 信号量保护的全局Zinc 变量

变量名

zafDisplay
zafDataManager
zafLanguageManager
zafCodeSet
zafLocale

全局变量zafApplication 是特殊的,因为所有全局的应用程序数据维持在其中。
zafApplication 作为一个任务变量被附加到GUI任务中,当不同的任务获得、丢失CPU控制
时,此变量的值随之改变。因此,如果外部任务需要和Zinc任务相交互,还要将
zafApplication作为一个任务变量。zafApplication 不由信号量保护,因为只有应用程序编
制者需要修改它。
因为zafApplication 是一个全局任务变量,从ISR级是不可以访问它的,例如从一个看门狗
定时器回调程序。替代增加zafApplication 为一个任务变量,传递一个对象的指针作为一个
任务函数的参数是可能的,但是这可能有一些副作用。当不同的任务运行时,
zafApplication 的值可能改变,并且几个库函数(例如ZafWindowObject::EventManager
( ))期望一个有效的zafApplication实例。即使你自己没有调用这些函数,你在使用的一些
库函数可能调用了。
参考“Zinc 参考手册” ,可获得上面所列的每个变量的描述。

任务优先级
在多任务应用程序里给不同的任务分配优先级是非常重要的。这儿没有通用的规则,只有
一些指导:
o 通常,GUI任务相对是低优先级。它必须高到能够维持响应,但更新屏幕没有
处理实时事件重要。因而,在Zinc演示里, Zinc任务用一个中等的高优先级产生(90 in
VxWorks)。
o 用来处理WindML 输入设备事件的任务用一个比Zinc任务稍微高一点的优先级
产生。
o 典型地,使所有的外部任务拥有比Zinc任务高的优先级。可能需要做一些试验
来确定一个好的优先级关系。

3.4 在Zinc(GUI)任务和外部任务之间的通信方法
在GUI任务和外部任务之间的通信可以大致分类为同步的和异步的,下列方法对程序员来
说是可用的:
o Zinc入口点
o 共享内存
o OS消息队列
为了达到一定的目的, 使用一些联合的方法常常是有意义的。另外,derived devices可被
用于任务间通信,参见“Derived 设备”。

利用Zinc入口点
这些程序启动GUI和外部任务之间的通信:
o 与Zinc通信的基本的入口点是ZafEventManager::Put( )程序。它用于在Zinc事
件队列上放置一个事件。这是一个异步方法,因此只能适用于可接受异步通信的场合。
o ZafApplication::BeginSynchronize( )和ZafApplication::EndSynchronize( )。
这两个程序自身并不是通信程序,但能确保直接通信方式访问Zinc是安全的。直接通信通
常由一个对象的Event( )函数来执行, 但是也可能采用其它的访问方式,例如事件对象更
新。
间接的通信可以使用ZafEventManager::Unblock( )函数来执行。如果使用一个derived 设
备或其它方法,该函数是有用的。它促成 Zinc任务解除阻塞,如果Zinc任务正在等待一个
事件来处理的话。

共享内存
在VxWorks中共享是易于实现的。为了安全地共享内存,最好让一个信号量和共享内存关
联。这样避免任务之间出现重写更新。
共享内存的使用通常不需要从Zinc 中可用的任何线程安全的入口点的使用。一个共同的例
外是当一个窗口对象的某个成员指向共享内存。例如,如果一个ZafButton的bitmapData
成员正指向共享内存,你不能安全地修改它,直到你已经确保它当前不在被Zinc任务使
用。你应该使用ZafApplication::BeginSynchronize( ) 和 ZafApplication::EndSynchronize
( ) 函数来保证你的任务是唯一用它的任务。

OS消息队列
VxWorks消息队列也可以从Zinc内部创建。这是一个“单向”的OS消息队列,可以用于下列
两者之一:
o 从Zinc任务到外部任务的通信
o 从外部任务到Zinc任务
不允许同时在两个方向上通信。

Derived设备
当你使用共享内存或消息队列作为通信方法时,Zinc需要与通信方法相合的一个方式。一
个便利的方式是在Zinc任务里用一个derived 设备。
一个derived 设备检查来自另一个任务的信息。每当ZafEventManager::Get( ) 函数被调
用,事件管理器轮询该设备,看看是否有新消息。这个 derived设备仅仅需要检查共享内
存或消息队列。
如果新信息可得到, derived 设备可以直接调用对象的Event( ) 函数在队列上面放置一个
新信息,或者自身处理这个信息。
一个derived 设备还能够用于从 Zinc任务到外部任务的通信。ZafEventManager::UnBlock
( )函数对这种通信方法是非常有用的。 如果没有事件被处理,Zinc 通常会阻塞。如果一
个 derived 设备被用于监听一个VxWorks消息队列,在发送一个消息到该队列后解除事件
管理器的阻塞将允许derived 设备以更及时的方式被轮询。


注意: derived设备自身不阻塞,也不会阻碍Zinc,使其halt,这很重要。

下面的例子说明了用一个VxWorks 消息队列来传递一个client 消息的的derived设备的适当
使用。
// 我的derived 类的构造函数
Communicator::Communicator(ZafDeviceState _state) :
ZafDevice(E_MOUSE, _state), mailToSend(false)
{
installed = true;
}
Communicator::~Communicator(void)
{
installed = false;
}

// 该类的轮询函数。事件管理器每次在ZAF事件队列中检查新消息时,
// 为每个附着的设备调用此轮询函数。
void Communicator::Poll(void)
{
if (!installed || DeviceState() == D_OFF)
return;
char queueMessage[MAX_MSG_LEN];
// 检查客户消息队列,并邮寄给ZAF的队列――如果有一个消息的话。
if (msgQReceive(clientMsgQueueID, queueMessage,
MAX_MSG_LEN, NO_WAIT) != ERROR)
{
ZafEventStruct qEvent(RECEIVE_MAIL);
qEvent.text = strdup(queueMessage);
zafEventManager->Put(qEvent);
}
// 这是一个hook,告诉设备发送任何返回的消息――只要有一个消息。
// 这个类可以被进一步增强,来处理一个消息列表,然后将它们同时发送出去。
// 这个类现在实际上每次只处理一个事件。
if (MailToSend())
{
// 发送消息
if (msgQSend(serverMsgQueueID, SEND_TEXT, sizeof(SEND_TEXT),
WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR)
zafEventManager->Put(SEND_MAIL_ERROR);
SetMailToSend(false);
}
}
3.5 选择合适的通信方法
上述每种关于Zinc任务的通信方法各有其强处和弱点。你选择的方法依赖于特殊的情形。各个选项按照复杂性递增的次序在此给出。
o 最简单的关于Zinc任务的通信方式是使用Zinc入口点,因为它们不需要Zinc 任务内部的任何专门代码(除了任何应用程序特殊的代码以外)。
可用的最简单的入口点是ZafEventManager::Put( )函数。 在大多数情况下它是足够使用的。然而,它有下列缺点:
a、 它枝一些通信进入到Zinc 任务内部
b、 它是异步的
c、 因为Zinc事件队列被ZafEventManager::Get( )和 ZafEventManager::Put( ) 函数从同步访问中保护,ZafEventManager::Put( ) 可能会阻塞。
如果异步通信是可接受的,但是阻塞的可能性不被接受,这儿有一对适合于通信的选项。
-- 第一个选项是使用ZafEventManager::Put( )函数,并且有一个单独的任务(此任务可以被阻塞)在Zinc 队列上面放置事件。这个任务可以监听一个OS 消息队列,最初的产生消息的任务将使用OS 消息队列来发送消息。
-- 另一个方法是创建一个设备来监听一个OS 消息队列。产生消息的任务发送一个消息给OS 消息队列,然后由derived 设备接收并解释。derived 设备可以放置一个事件在Zinc队列上面,或者简单地处理这个事件。两个方法都给应用程序增加了一些复杂性。
-- 如果需要同步通信,函数对 ZafApplication::BeginSynchronize( )和ZafApplication::EndSynchronize( )必须被使用。在调用 ZafApplication::BeginSynchronize( )之后,任何对Zinc对象的访问是安全的。这个方法是简单的,并且不需要在Zinc任务里加特殊的代码。函数ZafApplication:: BeginSynchronize( ) 通常会阻塞,因为底层的ISR程序不应使用本节描述的同步方法,应使用另一种可选的方法。

o 共享内存有对数据简单而直接地访问的优点。它还是从Zinc任务到外部任务的两种通信方法之一。然而,没有对数据访问进行保护的内建支持。一个保护及同步访问的方案必须被创建,并且被访问共享内存的所有任务使用。这样的方案容易遭遇阻塞情况。

o OS 消息队列是从Zinc任务到外部任务和从外部任务到的Zinc任务另一种可用的通信方法。当设置正确时,消息队列是一种不会带来阻塞问题的通信方法。消息队列被创建时,要么有足够的消息容量,要么有一个处理满的消息队列的机制。
阻塞不能被接受的情况下,使用OS消息队列是最好的通信方法。当然, Zinc任务和外部任务都将需要访问消息队列的代码。

4 性能改进
本节描述一些改进应用程序性能的方法。
多任务
通常的改进应用程序性能的方法是将一个应用程序分解为多个任务。尽可能多的GUI工作应该在Zinc任务中执行,所有的处理密集型的,非GUI工作在外部任务里完成。


注意:不是所有的应用程序都适合转换为多任务的。全面的关于多任务问题的讨论超出了本手册的范围,但是不正确的使用多任务可能对性能是有害的。

任务优先级
在一个多任务应用程序中,任务优先级是非常重要的。Zinc任务一个比其它大多数任务 (当然是紧要任务)的优先级要低。在嵌入式系统中,GUI是应用程序的相对低优先级的部分。然而,必须注意使 Zinc GUI仍然保持对用户的响应。

在WindML级别编程ZincDisplay 非常有效率,但它确实有一些开销。通常,旁路 Zinc 而直接用WindML API 编程是不被推荐的,但这样做有助于改进性能――如果做的正确的话。
当你仅仅使用Zinc API时,Zinc 假定为防止屏幕不纯负责。如果你使用WindML API,你就丢失了这个重要的优势。Zinc不能知道应用程序用WindML API在做什么。这可能导致裁剪问题、混乱的屏幕更新和其它类型的屏幕不纯。
有一种场合,应用程序直接使用WindML (例如,控制屏幕的固定部分)是安全的。直接使用 WindML 对于动画、视频流或其它WindML提供的功能(Zinc没有提供一个抽象层)是适合的。

5 Zinc Designer (.znc)文件
5.1 装载资源
如果目标机有磁盘存储器,不管是实际的硬盘,还是flash盘或其它设备,应用程序都可以使用一个Designer文件在运行时装载窗口。如果资源的文件路径 在ZafStorage 对象被创建时没有指定,应用程序将在第一个驱动器的根目录查找该资源文件。

5.2 ROMming Designer文件
一个Designer文件可以被应用程序使用,即使在目标机上实际没有磁盘设备。znc2rsrc实用程序可用于转换一个Designer文件到一个data array,进而被编译进应用程序。
编译一个Designer 文件到应用程序中减少了装载资源所用的时间。如果想这样, data array可以放在ROM里面。


注意: 编译一个Designer 文件到应用程序中意味着该文件只能被读。

5.3 多个任务访问相同的Designer文件
如果你试图从多个任务中访问一个Designer文件,你应该考虑以下几点:
o 如果所有任务只是需要读访问,那么最简单的访问方式是为每个任务创建一个单独的ZafStorage对象。
o 如果写访问是需要的,那么对ZafStorage对象的访问必须是同步的。在这种情况下,每个任务在重新获得对文件的访问时,必须重新定位到文件中的合适位置。这是因为另一个任务可能改变了当前ZafStorage的位置。

6 实时问题的其它方面
6.1 C和 C++集成
name Mangling
Zinc是一个C++库,但大多数的RTOS APIs是用C写的。因此,Zinc 应用程序很可能需要混合这两种语言。既然C++是C的扩展,两者有很近的关系。然而因为name mangling,可能会出现问题。
一个C++函数凭借Name mangling方法被编译,以便它能够被一个非C++连接器所链接。在name mangling 步骤期间,一个C++文件里的所有函数和函数调用使其返回类型和参数类型(通称为它们的特征)“编码”到函数符号里。这样允许更强壮的类型检查和函数重载。
这会引起一个连接过程问题。因为name mangling,一个来自C++ 文件的函数对一个C 文件里的函数――或周围其它路线――将由于符号不匹配而不能连接。一个连接器错误将被产生,说这个符号未定义。换句话说,如果连接器没有能力检定这个不匹配的参数列表,那就有可能发生一个运行时错误。
Name-mangled函数名问题会被正确地解决,只要照着下面做:
o 为了确保C++正确地看见函数原型,在原型声明周围放置extern "C" 包装。
这允许C++编译器创建对没有name mangling 的C函数的引用。换句话说, C++编译器将使用(与C编译器创建该函数所用的)同样的符号来引用该函数。此声明可用于单个函数,或者用于一组函数(通过将该组函数用大括号包起来),如下所示:
extern "C"
{
int foo1(int a);
int foo2(int a);
}
反过来也可以,如果需要,声明一个函数为extern "C++",不过这样不常见。
有关合起来使用C 和C++的更多详细资料,参考关于C++的书。

重载new( )和delete( )运算符
你可能想限制Zinc 使用的内存池,因为两个合理的原因:
o 隔离每个任务使用的内存,努力防止内存写满且重写了另一个任务拥有的内存。
o 确保一个任务中的问题不占用另一个任务需要的内存。
将内存分区不能保护一个系统或其它任务不受行为失常的任务的破坏,但有所帮助。因为Zinc 是一个C++库,内存分配可以通过重载new( ) 和delete( ) 运算符,使用内存分区来控制。
有关重载new( ) 和delete( ) 运算符的更多详细资料,参考关于C++的书。


返回 上一页 下一页   信息发布:工号01   转引自: 【 】 【打印】 【关闭

关于我们 ┋ 友情链接


深圳市福田区海滨广场福业大厦12C
电话:0755-88305880 25960580 传真:0755-88305880
Copyright©2005-2007 无忧电子开发网版权所有

粤ICP备05064233号