stdin、stdout、stderr都是FILE结构体的地址,编译器运行时初始化函数有一个FILE结构体数组_iob[3],里面分别保存着标准输入、输出设备对象的缓存区信息。VC6中FILE定义如下:
struct _iobuf {
char *_ptr; // 当前指针
int _cnt; // 剩余未处理大小
char *_base;// 缓存区基地址
int _flag; // 文件标志
int _file; // 文件描述符表索引
int _charbuf;
int _bufsiz; // 缓存区大小
char *_tmpfname; // 临时文件名
};
typedef struct _iobuf FILE;
stdout、stderr主要区别在重定向输出上,使用stderr输出的内容依旧会显示在屏幕上而不会重定向到其他设备里。
几个堆函数:
HeapCreate创建一个堆。
HeapAlloc堆中分配空间。
HeapFree堆中释放空间。
HeapDestory销毁一个堆。
毫无疑问的,Windows下的C编译器对malloc、free库函数的实现一定会调用上面的API,看一下VC6的大概过程:
在mainCRTStartup/wmainCRTStartup启动函数中有一个_heap_init函数,此函数会调用HeapCreate创建一块初始大小为BYTES_PER_PAGE字节不设上限的堆,并把堆句柄保存在变量_crtheap中。这就是我们main函数里使用的默认堆,以后无论调用malloc或free函数实际上都是对默认堆的申请或释放空间。
调试版本用HeapAlloc分配的堆空间,在数据地址前32字节有一个头部信息,如下:
struct HeapHeader {
DWORD dwBefore; // 上一个堆分配地址(指向头部,没有为0)
DWORD dwAfter; // 下一个堆分配地址(同上)
TCHAR *szFileName; // 调用堆分配的源码文件名
DWORD dwRow; // 文件中的行数
DWORD dwSize; //分配的数据大小
DWORD dwType; // 堆类型
DWORD dwCounts; // 此次调用的分配次数
DWORD dwCheckFlag; // 上溢检查标志,值为0xFDFDFDFD
// 类似的在数据结尾后紧跟着一个下溢标志。
};
调试版还有一个特点,对未分配的或已释放的堆空间,初始值0xFEEE(有些情况是0xDDDD)。