BREW中使用静态变量

之前有提到内存管理器,并未提到如何使用;长期以来,由于BREW执行文件格式的限制,无法使用静态变量和全局变量,关于如何打破这一限制,可能也有提到过。
首先来说静态变量的必要性,如果可以使用的话,我们就可以不用为程序中的某个变量该放在内存中的哪个位置而发愁了,我们可以集中力量解决某个问题,而不用考虑变量可不可用的问题。
理想总是完美的,目前所谓的解决办法是两个,一个是完美的,一个是不完美的。
先说说完美的解决办法,就是换编译器,将平时使用的ADS编译器,换成gcc编译器,通过编译脚本的控制,可以使用c++中的try..catch机制,静态变量,浮点运算等等,几乎没有限制,可以说是完美的,这种方法的一个缺点就是编译出来的容量太大,在我这边不管我如何的修改编译参数,我都无法使它保持和ADS差不多类似的容量。项目到最后需要减小容量的时候,最无奈的就是减小执行文件的容量。

再说不完美的解决办法,我们还是使用ADS的编译器,这样可以使可执行文件保持小的容量,无法使用try…catch机制,浮点运算等等,如果你不在意这些的话,解决的方法是使用const变量来解决,也就是所谓的常量,这样就有两个问题,常量是无法修改的(语法的定义)和常量是否有地址。关于后一个问题,常量在内存中有地址,并且,BREW中常量的地址和执行文件执行代码的地址是在一个段中。前一个问题,常量是无法修改的,这个状况要分两种,在模拟器上,常量被保存在一个特殊段中,这个段不可以被更改,而在真机中,常量和代码段在一起,虽然编译的时候,这个段指明不可被改写,但在运行时,并没有该限制。不过,模拟器中并没有不可使用静态变量等限制,因此,我们可以使用下面的宏来控制:

       #ifdef _WINS_
       #define _CONST_
       #else
       #define _CONST_ const
       #endif
       

使用的方法,类似下面的用法:

       static _CONST_ int int_var[] = {0};
       void fun()
       {
       int* p_int_var = (int*)int_var;
       *p_int_var = 5;
       int p2 = int_var[0]; //这是不安全的
       }
       

上面的写法不是漂亮的,但可以解决实际的问题。就像一把双刃剑,你必须时刻知道你在强制的改写常量,而且,这种方法可能会带来一些麻烦,比如上面的p2,你可能希望它的值是5,但不幸的是,你得到的可能是0,因为编译器帮你优化了(对于上面的写法,我目前没有发现这一问题,其他写法则发现存在,比如_CONST_ int* int_var = 0)。
最普通和繁琐的方法是将变量保存到一个结构中,而这个结构我们可以在任意时刻获得它的内存地址,通过强制转换或者其他手段,再获得变量,于是,我们瞄准了AEEApplet a;在注释中,它必须在程序入口结构的第一个位置(原因以后会说到),也就是说,它的地址就是程序入口结构的地址。我们在程序中可以在任何地方调用GETAPPINSTANCE()来获得它的地址,如果我们将变量放到它的后面,也可以获得改变量的地址,于是就有了下面的写法:

       class test_Instance
{
public:
        AEEApplet a; //!< First element of this structure must be AEEApplet
        int int_var;
};
void fun()
{
int* p_int_var = &(((test_Instance*)GETAPPINSTANCE())->int_var);
*p_int_var = 5;
int p2 = ((test_Instance*)GETAPPINSTANCE())->int_var; //这没有任何问题
}
       

上面的写法是安全的,不管使用的是模拟器还是真机,都是一样的。
对于ADS的两种解决办法,我没有一个统一的定论,我在项目中,两种方法都使用到,如何方便安全如何使用吧。从根本上讲,编译器支持才是王道。

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你