2.3.4 在Windows中使用printf
那些有使用C语言字符模式以及命令行经验的程序员通常非常喜欢使用printf函数。所以在Kernighan和Ritchie的"hello,world"程序中使用printf函数一点也不让人惊讶,即使更简单的方法也许是使用puts函数。大家都知道"hello,world"的增强版需要输出格式化后的文字,所以不如干脆在一开始就使用printf函数。
有个坏消息是:不能在Windows程序中使用printf函数。虽然可以在Windows中使用绝大多数的C语言运行库函数--实际上,相较于Windows中相应的函数,很多程序员更愿意使用C的内存管理和文件I/O函数--但是Windows不存在标准输入(standard input)和标准输出(standard output)的概念。所以你可以在Windows程序中使用fprintf函数,但不能使用printf函数。
而好消息则是:你仍然可以使用sprintf和sprintf系列的其他函数来显示文本。除了将格式化后的字符串内容输出到函数第一个参数所提供的字符串缓冲区以外,这些函数的功能和printf函数一样。然后就可以用这个字符串做任何事(例如,可以将输出字符串传给MessageBox)。
如果你从来没使用过sprintf(像我一样,开始写Windows程序时,也没用过此函数),这里有一个简短的介绍。回忆一下,printf函数是如下定义的:
- int printf (const char * szFormat, ...);
第一个参数是一个格式字符串,后面是与格式字符串中的代码相对应的不同类型的多个参数。
sprintf函数定义如下:
- int sprintf (char * szBuffer, const char * szFormat, ...);
第一个参数是一个字符缓冲区;后面是一个格式字符串。sprintf并不是将格式化结果写到标准输出,而是将其存入szBuffer。该函数返回该字符串的长度。在字符模式编程环境中,语句:
- printf ("The sum of %i and %i is %i", 5, 3, 5+3);
的功能等同于以下语句:
- char szBuffer [100];
- sprintf (szBuffer, "The sum of %i and %i is %i", 5, 3, 5+3);
- puts (szBuffer);
而在Windows中,需要使用MessageBox而不是puts来显示结果。
几乎每个人都有这样的经验,一旦格式字符串与被格式化的变量不合,就可能会导致printf出错并可能造成程序崩溃。使用sprintf时,除此之外还要考虑一点:定义的字符串缓冲区必须足够大以存放结果。Microsoft的专用函数_snprintf解决了这一问题,此函数引进了另一个参数来指定字符缓冲区的大小。
sprintf还有一个变形函数vsprintf,它只有三个参数。当需要对可变参数执行像printf一样的格式化时,可以用vsprintf来实现你自己的函数。vsprintf的前两个参数与sprintf相同:一个用于保存结果的字符缓冲区和一个格式字符串。第三个参数是指向待格式化的参数数组的指针。实际上,该指针指向在堆栈中供函数调用的变量。宏va_list、va_start和va_end(在STDARG.H中定义)帮助处理堆栈指针。我们在本章最后的SCRNSIZE程序中表明了如何使用这些宏。sprintf函数可以用vsprintf函数这样编写:
- int sprintf (char * szBuffer, const char * szFormat, ...)
- {
- int iReturn;
- va_list pArgs;
-
- va_start (pArgs, szFormat);
- iReturn = vsprintf (szBuffer, szFormat, pArgs);
- va_end (pArgs);
-
- return iReturn;
- }
va_start宏将pArg设为指向一个在堆栈参数szFormat之上的堆栈变量。
因为很多早期的Windows程序使用了sprintf和vsprintf,最终导致Microsoft在Windows API中增添了两个相似的函数。Windows版的wsprintf和wvsprintf函数在功能上与sprintf和vsprintf相同,不同的是它们不能处理浮点格式。
当然,随着宽字符的引入,sprintf系列的函数增加了许多,使得函数名让人困惑。下表列出了Microsoft版的C语言运行库和Windows所支持的所有sprintf类函数。
|
ASCII |
宽 字 符 |
通 用 |
可变数目的参数 |
|
|
|
标准版 |
sprintf |
swprintf |
_stprintf |
最大长度版 |
_snprintf |
_snwprintf |
_sntprintf |
Windows版 |
wsprintfA |
wsprintfW |
wsprintf |
参数数组的指针 |
|
|
|
标准版 |
vsprintf |
vswprintf |
_vstprintf |
最大长度版 |
_vsnprintf |
_vsnwprintf |
_vsntprintf |
Windows版 |
wvsprintfA |
wvsprintfW |
wvsprintf |
在宽字符版的sprintf函数中,字符串缓冲区被定义为宽字符串。在所有的宽字符版的函数中,格式字符串必须是宽字符串。不过,确保传递给这些函数的其他字符串也是宽字符串则是你的责任。
【责任编辑:
云霞 TEL:(010)68476606】