本文是我学习《windows程序设计》(第5版)的笔记,方便以后查阅。如果被您看到并且对您有用的话,那再好不过了。本文不涉及具体的讲解,详细的讲解请看《windows程序设计》(第5版)这本书,它才是经典之作!
这本书是1998年出的,当时Unicode还没有成为国际标准,现在肯定是标准了。Unicode的作用:能够使计算机实现跨语言、跨平台的文本转换及处理。
先看代码:
#include <windows.h> #include <tchar.h> #include <stdio.h> int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...) { TCHAR szBuffer [1024] ; //定义缓冲区大小 va_list pArgList ;//定义一个va_list型的变量,这个变量是指向参数的指针 // The va_start macro (defined in STDARG.H) is usually equivalent to: // pArgList = (char *) &szFormat + sizeof (szFormat) ; va_start (pArgList, szFormat) ;//用va_start宏初始化变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数. // The last argument to wvsprintf points to the arguments _vsntprintf (szBuffer, sizeof (szBuffer) / sizeof (TCHAR), szFormat, pArgList) ; // The va_end macro just zeroes out pArgList for no good reason va_end (pArgList) ;//用va_end宏结束可变参数的获取,将指针置为无效 return MessageBox (NULL, szBuffer, szCaption, 0) ;//把变量在消息框显示 } //windows入口函数 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { int cxScreen, cyScreen ; //获取屏幕的分辨率 cxScreen = GetSystemMetrics (SM_CXSCREEN) ;//横向 cyScreen = GetSystemMetrics (SM_CYSCREEN) ;//纵向 //调用MessageBoxPrintf,这里参数变成了四个 MessageBoxPrintf (TEXT ("ScreenSize"), TEXT ("The screen is %i pixels wide by %i pixels high."), cxScreen, cyScreen) ; return 0 ; }
运行结果如下:
关于_vsnprintf()函数:
函数声明:
int vsnprintf(char*str,size_tsize,constchar*format,va_listap);
参数说明:
1. char *str [out],把生成的格式化的字符串存放在这里.
2. size_t size [in],str可接受的最大字节数,防止产生数组越界.
3. const char *format[in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。
4. va_list ap [in],va_list变量.
函数功能:将可变参数格式化输出到一个字符数组。
用法类似于vsprintf,不过加了size的限制,防止了内存溢出(size为str所指的存储空间的大小)。
返回值:执行成功,返回写入到字符数组str中的字符个数(不包含终止符),最大不超过size;执行失败,返回负值,并置errno.
备注:
linux环境下是:vsnprintf
VC6环境下是:_vsnprintf
通过_vsnprintf()函数就把MessageBoxPrintf函数第二个参数的字符串值存入了第一的缓冲区szBuffer里
关于宏va_list,va_start,va_end:
这里要知道两个事情:|-----------------------------------------|
|-------最后一个可变参数----------| ->高内存地址处
|-----------------------------------------|
|-----------------------------------------|
|--------第N个可变参数-------------|
|-----------------------------------------|
|-----------------------------------------|
|--------第一个可变参数------------| ->va_start(pArgList,szFormat)后pArgList所指的地方
|-----------------------------------------|
|--------最后一个固定参数---------|
|-----------------------------------------|
|-----------------------------------------|
|-----------------------------------------|
|---------第一个固定参数-----------| -> 低内存地址处
|-----------------------------------------|
|-----------------------------------------|
va_start,函数名称,读取可变参数的过程其实就是在堆栈中,使用指针,遍历堆栈段中的参数列表,从低地址到高地址一个一个地把参数内容读出来的过程·
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减.
总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.
堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.
GetSystemMetrics ()函数:用于得到被定义的系统数据或者系统配置信息.
参数SM_CYSCREEN :以像素为单位计算的屏幕尺寸
(第4章中作者将具体讲解)