win32 编程之调试输出

来源:互联网 发布:骑士vs火箭数据 编辑:程序博客网 时间:2024/05/16 19:51

在windows下编程时,不能再使用printf了,需要使用sprintf、wsprintf,或者采用MessageBox弹出对话框来输出相应的值。

#include <stdarg.h>int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...){     TCHAR   szBuffer [1024] ;      va_list pArgList ;          // The va_start macro (defined in STDARG.H) is usually equivalent to:          // pArgList = (char *) &szFormat + sizeof (szFormat) ;     va_start (pArgList, szFormat) ;     _vsntprintf (szBuffer, sizeof (szBuffer) / sizeof (TCHAR), szFormat, pArgList) ;     va_end (pArgList) ;// The va_end macro just zeroes out pArgList for no good reason     return MessageBox (NULL, szBuffer, szCaption, 0) ;}

上面这段代码来自《windows程序设计》,对MessageBox稍微进行了改进。函数前的CDECL很少见,其实它和_cdecl是一样的,只是名字不同。MessageBoxPrintf使用方法如下:

MessageBoxPrintf (TEXT ("ScrnSize"),TEXT ("The screen is %i pixels wide by %i pixels high."),100, 200) ;

windows有很多输出函数,常用的是sprintf、wsprintf,这些函数不能像C语言中的printf函数那样,可以直接输出,而是把数据输出到一个缓冲区,再通过MessageBox将缓冲区的内容显示出来。上面的_vsntprintf的原理也是一样,只是它支持的缓冲区更大一些,并且支援ascii与unicode字符。

比较难理解其实是那个va_list、va_start、va_end,还有它们的兄弟va_arg函数,这些函数来自于<stdarg.h>,在vc++6.0中,实现代码如下:

typedef char *  va_list;#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )#define va_end(ap)      ( ap = (va_list)0 )

上面这几句代码并不好理解,除了最后那个va_end回收内存好理解以外,其它代码都值得细究一下。

1,关于(sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1),主要解决的就是“内存对齐”,因为在32位操作系统上int是占32位(4个字节),但是原来的系统不一定是4个字节,有可能是2个字节,这段代码就是来解决如果某编译平台上int占4个以下的字节时,把它提升为占4个字节。如sizeof(n)为2,则(2+3)&~3=4.

2,va_start的作用,MessageBoxPrintf的注释大概也清楚了。(va_list)&v指的是"The screen is %i pixels wide by %i pixels high."的首字符地址,而+ _INTSIZEOF(v)就相当于是将字符指针加到“.”(这个字符串的最后一个字符)的下一个字符,即执行va_start函数后,ap实际上已经指向了参数100的地址。

3,需要注意的是va_start的第二个参数,一定要是“...”之前的那个参数(此处即为szFormat)。

但是上面的程序没有用到va_args这个函数,下面再举一个例子,下面的代码完成的一个精简版的printf函数,它可以指定任意个输出参数:

void minprintf(char *fmt,...){va_list ap;char *p,*sval;int ival;double dval;va_start(ap,fmt);for(p = fmt;*p;p++){if(*p != '%'){putchar(*p);continue;}switch(* ++p){case 'd':ival = va_arg(ap,int);printf("%d",ival);break;case 'f':dval = va_arg(ap,int);printf("%d",dval);break;case 's':for(sval = va_arg(ap,char *); *sval;sval++){putchar(*sval);}break;default:putchar(*p);break;}}va_end(ap);}
这个代码来自《C程序设计语言》,很经典,我们可以这样调用:

minprintf("===%d==%d===%d\n",15,30,45);

3,va_args这个函数比较难理解,(ap += _INTSIZEOF(t)) - _INTSIZEOF(t)这个代码有两个意思。

(1),ap指向下一个参数的地址,作用代码(ap += _INTSIZEOF(t)) 。因为上面的代码调用va_start使ap指向15的地址,所以调用va_args后,ap就指向第二变参,即30的地址;

(2),返回ap指向的前一个地址(即参数15的地址),因为此时ap已经指向了下一个参数的地址,所以要 - _INTSIZEOF(t)。而(t *)作用是将返回的地址轮换成一个指针(即15的地址),再用*取得这个指针指向的值(即15)。





0 0