C语言中经常被误解的3个常用工具:printf库函数族、varargs和stdarg工具。后两者主要用于编写那些随调用场合的不同,其参数的数目和类型也不同的函数。
printf函数族
#include <stdio.h>
main() {
printf("Hello world\n");
}
printf函数的第一个参数是关于输出格式的说明,它是一个描述了输出格式的字符串。这个字符串遵循通常的C语言惯例,以空字符(即\0)结尾。我们把这个字符串写成字符串常量的形式(即用双引号括起来),就能够自动保证它以空字符结尾。
printf函数是把数据写到标准输出,fprintf函数则可以把数据写到任何文件中。需要写入的特定文件,将作为fprintf函数的第一个参数,它必须是一个文件指针。因此
printf(stuff);
从意义上来说就等效于
fprintf(stdout, stuff);
sprintf函数的第1个参数是一个指向字符数组的指针,sprintf函数将把其输出数据写到这个字符数组中。编程人员应该确保这个数组足够大以容纳sprintf函数所生成的输出数据。sprintf函数其余的参数与printf函数的参数相同。sprintf函数生成的输出数据总是以空字符收尾,如果希望在输出数据中出现一个空字符,我们可以显式地使用%c格式项把它打印出来。
这3个函数的返回值都是已传送的字符数。对于sprintf的情形,作为输出数据结束标志的空字符并不计入总的字符数。如果printf或fprintf在试图写入时出现一个I/O错误,将返回一个负值。因为格式字符串决定了其余参数的类型,而且可以到运行时才建立格式字符串,所以要检查printf函数的参数类型是否正确是异常困难的。
printf("%d\n", 0.1);
printf("%g\n", 2);
最后得到的结果可能毫无意义,而且在程序实际运行之前,这些错误既有可能不会被编译器检测到,而成为“漏网之鱼”。
fprintf("error\n");
本意是使用fprintf函数输出一行出错信息到stderr,但是一时大意忘记写stderr,而fprintf函数会把格式字符串当做一个文件结构来处理,这种情况下就很可能出现内核转储的后果!
A.1.1 简单格式类型
每个格式项都是以格式码结束。
%d的含义是以十进制形式打印一个整数,例如
printf("2 + 2 = %d\n", 2 + 2);
%u要求打印无符号十进制整数。
printf("%u\n", -37);
char类型和short类型会被自动扩展为int类型,在把char类型视为有符号类型整数的机器上,这一点经常会引起令人吃惊的后果。 例如下面的例子:
char c;
c = -37;
printf("%u\n", c);
/*
** 有符号字符和无符号字符。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
char ch = -37;
unsigned int ui = (unsigned char)ch;
unsigned int ui2 = (unsigned)ch;
printf( "ch = %c, ch = %d\n", ch, ch );
printf( "(unsigned char)ch = %c, (unsigned char)ch = %d\n", (unsigned char)ch, (unsigned char)ch );
printf( "ui = %d, ui = %u\n", ui, ui );
printf( "(unsigned)ch = %c, (unsigned)ch = %d\n", (unsigned)ch, (unsigned)ch );
printf( "ui2 = %d, ui2 = %u\n", ui2, ui2 );
printf( &