_cinit
在完成了_setargv() 以及_setenvp() 之后,进入到_cinit 函数。该函数的注释很短,就一句“do C data initialize”,让人完全摸不着头脑。不过不用着急,可以阅读_cinit 函数的实现来加以分析。
_cinit 函数很短,大致上分为三个步骤:
1. _fpmath() 或者 (*_FPinit)();
2. _initterm( __xi_a, __xi_z );
3. _initterm( __xc_a, __xc_z );
第一步
是可选的,_FPinit 主要用来初始化浮点运算。只有当用户写的代码中出现了浮点运算,_FPinit 才会被定义。关于_FPinit 由于MSDN 上没相关资料,在此不做深究。
第二步和第三步
是分别对C和C++程序做初始化。_initterm 接受两个指针作为参数,这两个指针中间的内存区域是一张函数指针表。_initterm 会从第一个指针开始,慢慢向后寻找,直到第二个指针结束,中间如果找到了一块内存表示一个函数指针,则执行该函数。
/*
* pointers to initialization sections
*/
extern _PVFV __xi_a[], __xi_z[]; /* C initializers */
extern _PVFV __xc_a[], __xc_z[]; /* C++ initializers */
void _initterm ( _PVFV * pfbegin, _PVFV * pfend )
{
/*
* walk the table of function pointers from the bottom up, until
* the end is encountered. Do not skip the first entry. The initial
* value of pfbegin points to the first valid entry. Do not try to
* execute what pfend points to. Only entries before pfend are valid.
*/
while ( pfbegin < pfend )
{
/*
* if current table entry is non-NULL, call thru it.
*/
if ( *pfbegin != NULL )
(**pfbegin)();
++pfbegin;
}
}
_initterm( )
先来看看第二步、第三步中都做了什么。这里继续沿用一段空的C代码(main函数中没有任何东西)来build成exe,随后运行该exe,并且OD到_cinit 内部。
这里的两个call 分别表示调用了 _initterm( __xi_a, __xi_z ) 和_initterm( __xc_a, __xc_z ) 。对应的有:
__xi_a = 00406008
__xi_z = 00406010
和
__xc_a = 00406000
__xc_z = 00406004
继续跟进可以发现,在00406008 至 00406010之间仅有一个函数指针,指向__initmbctable()函数。
__initmbctable() 在第(4)篇_setargv 中曾经有过介绍,它会创建一个新的
_setargv 中已经调用过了该函数,
并将__mbctype_initialized 被设置为1 ,因此这里
__initmbctable()实际上不会重复创建。
在00406000 至 00406004 之间没有函数指针,实际上什么也不执行。
因此,对于空的C程序:
- _initterm( __xi_a, __xi_z ) ------> 调用__initmbctable() ------> 实际上没做什么
- _initterm( __xc_a, __xc_z ) ------> 不产生调用
现在来换一段C程序:
#include <stdio.h>
#include <math.h>
void main()
{
int a = 5;
double b = sqrt(a);
printf("%f\n",b);
}
跟踪的结果为:
- _initterm( __xi_a, __xi_z ) ------> 先后调用__initstdio
,__initmbctable
- _initterm( __xc_a, __xc_z ) ------> 不产生调用
这里由于调用了stdio标准库,因此为了stdio能够正确的工作,需要进行初始化。暂时没有找到关于initstdio
函数的资料,暂时不作深究。
至于为什么第二个initterm 不会产生函数调用,这是因为第二个initterm 是用于C++ data initializations,所以在C 程序中毫无作为。来看一段简单的C++ 代码:
int foo(){
int a=1;
int b=9;
return a+b;
}
int a = foo();
void main()
{
}
注意这里的全局变量a,C语言里是不会允许这种写法的,在C中全局变量只能用常量进行赋值。准确说C中的全局变量在编译期就需要被确定,链接器会把所有的全局变量都放进PE的data区域。说白了,这些全局变量都是直接写死在PE中的。
但是C++ 中确允许像上面那样动态赋值,原因就在于第二次调用 initterm 时,会调用foo函数为A进行初始化。对于上面的C++代码:
- _initterm( __xi_a, __xi_z ) ------> 调用__initmbctable() ------> 实际上没做什么
- _initterm( __xc_a, __xc_z ) ------> 调用foo()函数
利用_initterm( __xc_a, __xc_z ) 对C++ data 进行 initialization 有点儿复杂,这里不讨论。
另参考:
http://blog.donews.com/x140yu/archive/2005/05/26/399256.aspx
分享到:
相关推荐
cinit 为您的C项目创建文件结构和Makefile。 Makefile默认为c99和clang。 用法 使用make编译程序,并使用以下命令调用它: ./cinit 结构 该命令将创建以下结构: <project>/ ├─ Makefile ├─ src/ │ ├─ ...
extern uint32_t I2CInit_0( uint32_t I2cMode ,int SpeedMode) ;//I2C0支持快速模式和标准模式 extern uint32_t I2CInit_1( uint32_t I2cMode ); extern uint32_t I2CInit_2( uint32_t I2cMode ); uint8_t I2C_...
从宽带响应中减去 IR 响应可得出人眼响应的近似值。 用法 在 user_init 调用中: i2cinit(); TSL2561_init(TSL2561_ADDR_F); 注意:如果您的设备地址引脚连接到 VCC 或 GND,请使用 TSL2561_ADDR_L 或 TSL2561_...
DSP CCS初学调试问题精品总结大全!向高手学习,才会成为高手!
cinit是一种快速,并行引导的真正依赖项,支持具有配置文件支持的init系统。
<span xss=removed>pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader.__cinit__ (pandas\_libs\parsers.c:4209)() pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader._setup_parser_...
支持Meag8、C8051等系列MCU的...extern bool CG_EPPROM24CInit(const eEPPROM24Ctype DeviceType); /*测试储存器*/ extern bool CG_EPPROM24CTest(const eEPPROM24Ctype DeviceType , tEPPROM24CTESTRET * Result);
现在网上这个资源越来越少了 大家下载后都保存下哦
void LCD_blockClear(kal_uint16 startx,kal_uint16 starty,kal_uint16 endx,kal_uint16 endy, kal_uint16 data) { kal_uint16 LCD_x; kal_uint16 LCD_y; write_command(0x2A); //X Address Setup ...
此项目为了尽快的简单易上手,以及方便文章讲解,大部分逻辑都在主应用和子应用的main.js来回施展,实际项目应用可不要如此粗暴,要有优雅的架构设计。 微前端进阶实战项目:基于vue3.0-beta及qiankun2.0极速尝鲜! ...
23.1 cinit(8234) 346 23.2 getc(0930) 346 23.3 putc(0967) 347 23.4 字符集 347 23.5 图形字符 348 23.6 UNIX惯例 349 23.7 maptab(8117) 349 23.8 partab(7947) 349 第24章 交互式终端 351 24.1 接口 351 24.2 ...
23.1 cinit(8234) 346 23.2 getc(0930) 346 23.3 putc(0967) 347 23.4 字符集 347 23.5 图形字符 348 23.6 UNIX惯例 349 23.7 maptab(8117) 349 23.8 partab(7947) 349 第24章 交互式终端 351 24.1 接口 351 24.2 ...
.cinit 存放程序中的变量初值和常量
项目地址: &&部署教程:最终效果项目启动npm run yinit // 使用yarn下载依赖,推荐npm run cinit // 使用cnpm下载依赖npm run init // 或 使用npm下载依赖npm run serve // 运行全部项目yarn serve y // yarn运行...
面部表情识别 依赖=> pip安装opencv-python pip安装tensorflow pip安装numpy 点安装熊猫点安装keras 点安装亚当点安装kwargs 点安装cinit 用于培训和测试的数据集=>