百科知识

详解printf输出格式,轻松掌握C语言打印技巧

printf函数作为C语言学习过程中的启蒙函数,其简单性与复杂性并存(能够处理所有C基础数据类型的输出),使得许多人在学习后并未充分利用其功能。本文旨在对printf函数的用法进行系统梳理,并涵盖C99标准的相关特性。在C语言中,printf()、fprintf()、sprintf()这三种函数均用于向输出流中写入可变数量的数据项,并借助格式化字符串来规范输出格式。需要注意的是,这三者仅在输出目标位置上存在差异,其他功能完全一致:printf()输出到标准输出stdout,fprintf()输出到指定的FILE *stream流中,sprintf()则写入到字符串内。本文将重点介绍printf()函数的详细使用方法。

printf函数依据格式化字符串(format)的规范,将可变参数按照指定格式打印至stdout。该格式化字符串由普通字符和转换说明符构成,其中转换说明符以%符号开头,其结构最多包含五部分,方括号[]内的内容为可选部分。

下文将提供一个关于转换说明符构成的概览图示,随后将从转换说明符的最后部分—— specifier开始进行详细解析。

转换说明符的最后部分是最为关键且必须指定的部分,而前四个部分则具有可选性。

d、i:用于表示有符号的十进制整数;u、o、x、X:均为无符号类型,分别对应十进制、八进制、十六进制小写、十六进制大写表示;f、F:用于浮点数的输出,其中浮点数的默认精度为小数点后六位。特别地,F格式是在C99标准后才被引入的;对于实数而言,f和F在功能上并无差异,主要用途是区分无穷大(infinity)和NaN(not a number)的表示。以下示例将展示C99标准中关于INF、NAN等特殊数值的产生与打印方式。

e和E:采用科学计数法表示double类型数值,两者的主要区别在于输出时使用大写E还是小写e。此外,在打印INFINITY和nan(“0”)时,e格式输出为inf,而E格式则输出为INF;g:根据数值大小自动选择使用固定点格式(%f)或科学计数法格式(%e),目标是以最简洁的方式呈现数值。其具体工作原理如下:确定精度值 (precision):若在 %g 格式说明符中明确指定了精度值,则采用该值;若未指定,则默认精度为6;当精度值为0时,等同于精度为1。计算科学计数法下的指数 (exponent):假设使用 %e 格式说明符,首先计算出该浮点数的指数。

根据指数大小选择输出格式:若指数exp满足 -4 <= exp < precision,则采用固定点格式 %f,并使用 precision – (exp + 1) 作为精度值;否则,采用科学计数法格式 %e,并使用 precision – 1 作为精度值。去除尾随零和小数点:除非使用 # 标志,否则会从结果的小数部分中移除尾随零,且若小数部分全部为零,则同时移除小数点。值得注意的是,%g的输出结果可能与 %f 或 %e 中较短的格式不完全一致。其选择格式基于指数大小,而非单纯比较输出长度。

G:与g类似,但会在E和F之间选择大写形式。a和A:分别对应十六进制浮点数(A为大写),属于C99标准新增特性,用于以十六进制格式输出浮点数,从而更精确地展示浮点数的内部表示方式。其具体结构包含四部分:符号:’+’表示正数,’-‘表示负数。十六进制前缀:0x。尾数:包含小数点的十六进制数,分隔整数部分与分数部分。指数:以p表示,后接十进制数,指示2的幂次方。以下示例将演示a和A的表示方法,适用于double和float类型。

那么,0x1.921f9f01b866ep+1如何表示3.14159呢?其计算过程如下:小数点后的16的负次幂与小数点前的16的正次幂相乘,

计算结果为1.570795,需再乘以指数部分1.570795*2^(1)=3.141590。

c:将无符号整数转换为字符形式输出;s:字符串输出。若指定精度值(此时表示最大字节数),则在达到精度值或遇到空字符时停止写入。p:将void *类型的指针转换为可打印形式;输出结果显示,64位系统下指针长度为8字节。

n:对应实参必须是指向int类型对象的指针,不产生实际输出,而是将printf已打印的字符数量存储在对应的int类型指针指向的位置。上述示例将字符串 “Hello, world! ” 输出到控制台,并将已写入的字符数量(13个字符,含空格)存储至count变量中。

%:在%符号后追加一个%,将在stdout中输出%字符。-:指定打印时左对齐,默认右对齐;+:有符号数字始终以+或-开头,默认仅负数显示-号,正数不显示+号;空格:对于有符号数字,若为正数,则在数字前添加空格。(+标志优先于空格标志)#:与转换说明符specifier为o、x、X配合使用时,输出数字将带有0、0x、0X前缀,使八进制和十六进制输出更直观;与转换说明符specifier为a,A,e,E,f,F,g,G配合使用时,用于浮点数输出始终显示小数点,即使小数部分为零。0:使用前导0在数值字段宽度内进行填充。若转换说明符specifier为d、i、o、u、x、X且指定了精度,则可忽略0标志。若打印数据位数不足,printf()将进行填充(默认在数据左侧添加空格,实现右对齐)。若数据位数超出指定宽度,则不会进行裁剪,完整显示数据。最小字段宽度可设置为整数,也可用*号表示,*号的含义是从printf()函数的实参中获取输出字段宽度,而非在格式化字符串中指定。

.precision:假设定义了精度值,并设为number。搭配整数相关转换说明符(d、i、o、u、x、X),精度值表示最小位数(数据不足时添加前导0)。若实际数据长度超过number,则不会截断,完整显示。注意:若number为0且printf要打印的数据为0,此时不显示0。搭配a、 A、e、E、f、F转换说明符,number指定小数点后显示的位数(默认为6位);搭配g和G转换说明符,number表示有效数字的个数;搭配s转换说明符,number表示打印字符串的最大字节数;若number非具体数字,而是*号,则表示从printf()函数的实参中获取number值,而非在格式化字符串中指定。长度修饰符与转换说明符结合使用,共同指定实参的类型。

第一行展示未指定长度修饰符时,各转换说明符对应的默认数据类型;hh、ll、j、z、t均为C99标准新增特性。引入z和t后,对size_t和ptrdiff_t类型值的输出更为便捷。