C 07_C语言输入输出格式控制符

一、二进制数、八进制数和十六进制数的表示

1.1 不同进制数的表示

一个数字默认就是十进制的,表示一个十进制数字不需要任何特殊的格式。但是,表示一个二进制、八进制或者十六进制数字就不一样了,为了和十进制数字区分开来,必须采用某种特殊的写法,具体来说,就是在数字前面加上特定的字符,也就是加前缀。

1.2 二进制

二进制由 0 和 1 两个数字组成,使用时必须以0b或0B(不区分大小写)开头,例如:

1
2
3
4
//合法的二进制
int a = 0b101;  //换算成十进制为 5
int b = -0b110010;  //换算成十进制为 -50
int c = 0B100001;  //换算成十进制为 33

注意,标准的C语言并不支持上面的二进制写法,只是有些编译器自己进行了扩展,才支持二进制数字。换句话说,并不是所有的编译器都支持二进制数字,只有一部分编译器支持,并且跟编译器的版本有关系。

1.3 八进制

八进制由 0~7 八个数字组成,使用时必须以0开头(注意是数字 0,不是字母 o),例如:

1
2
3
4
//合法的八进制数
int a = 015;  //换算成十进制为 13
int b = -0101;  //换算成十进制为 -65
int c = 0177777;  //换算成十进制为 65535

1.4 十六进制

十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,使用时必须以0x或0X(不区分大小写)开头,例如:

1
2
3
4
//合法的十六进制
int a = 0X2A;  //换算成十进制为 42
int b = -0XA0;  //换算成十进制为 -160
int c = 0xffff;  //换算成十进制为 65535

二、格式控制符

2.1 格式控制符列表

格式控制符 是以%开头,后跟数据类型控制说明字符的站位符。 格式控制符:

格式控制符 说明
%c 输出一个单一的字符
%hd、%d、%ld 以十进制、有符号的形式输出 short、int、long 类型的整数
%hu、%u、%lu 以十进制、无符号的形式输出 short、int、long 类型的整数
%ho、%o、%lo 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数
%#ho、%#o、%#lo 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数
%hx、%x、%lx 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数,输出的十六进制数字小写
%hX、%X、%lX 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数,输出的十六进制数字大写
%#hx、%#x、%#lx 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数,输出的十六进制数字和前缀都小写
%#hX、%#X、%#lX 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数,输出的十六进制数字和前缀都大写
%f、%lf 以十进制的形式输出 float、double 类型的小数
%e、%le 以指数的形式输出 float、double 类型的小数,输出结果中的 e 小写
%E、%lE 以指数的形式输出 float、double 类型的小数,输出结果中的 E 大写
%g、%lg 十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0,当以指数形式输出时 e 小写
%G、%lG 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0,当以指数形式输出时 E 也写
%s 输出一个字符串
%p 输出指针(内存地址)

在编写代码的过程中,我建议将格式控制符和数据类型严格对应起来,养成良好的编程习惯。 当使用%d输出 short,或者使用%ld输出 short、int 时,不管值有多大,都不会发生错误,因为格式控制符足够容纳这些值。 当使用%hd输出 int、long,或者使用%d输出 long 时,如果要输出的值比较小(就像上面的情况),一般也不会发生错误,如果要输出的值比较大,就很有可能发生错误。

严格来说,格式控制符和整数的符号是紧密相关的,具体就是:

  • %d 以十进制形式输出有符号数;
  • %u 以十进制形式输出无符号数;
  • %o 以八进制形式输出无符号数;
  • %x 以十六进制形式输出无符号数。

printf 并不支持,也没有对应的格式控制符以八进制和十六进制形式输出有符号数。 下表全面地总结了不同类型的整数,以不同进制的形式输出时对应的格式控制符(–表示没有对应的格式控制符)。

short int long unsigned short unsigned int unsigned long
八进制 %ho %o %lo
十进制 %hd %d %ld %hu %u %lu
十六进制 %hx 或者 %hX %x 或者 %X %lx 或者 %lX
  • 当以有符号数的形式输出时,printf 会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位;
  • 当以无符号数的形式输出时,printf 也会读取数字所占用的内存,并把所有的内存都作为数值位对待。

对于一个有符号的正数,它的符号位是 0,当按照无符号数的形式读取时,符号位就变成了数值位,但是该位恰好是 0 而不是 1,所以对数值不会产生影响,这就好比在一个数字前面加 0,有多少个 0 都不会影响数字的值。 如果对一个有符号的负数使用 %o 或者 %x 输出,那么结果就会大相径庭。

2.2 printf() 格式控制符的完整形式

printf() 格式控制符的完整形式如下:

1
%[flag][width][.precision]type

[ ] 表示此处的内容可有可无,是可以省略的。

  1. type 表示输出类型,比如 %d、%f、%c、%lf,type 就分别对应 d、f、c、lf;再如,%-9d中 type 对应 d。 type 这一项必须有,这意味着输出时必须要知道是什么类型。

  2. width 表示最小输出宽度,也就是至少占用几个字符的位置;例如,%-9d中 width 对应 9,表示输出结果最少占用 9 个字符的宽度。

当输出结果的宽度不足 width 时,以空格补齐(如果没有指定对齐方式,默认会在左边补齐空格);当输出结果的宽度超过 width 时,width 不再起作用,按照数据本身的宽度来输出。

  1. .precision 表示输出精度,也就是小数的位数。 当小数部分的位数大于 precision 时,会按照四舍五入的原则丢掉多余的数字; 当小数部分的位数小于 precision 时,会在后面补 0。

另外,.precision 也可以用于整数和字符串,但是功能却是相反的:

  • 用于整数时,.precision 表示最小输出宽度。与 width 不同的是,整数的宽度不足时会在左边补 0,而不是补空格。
  • 用于字符串时,.precision 表示最大输出宽度,或者说截取字符串。当字符串的长度大于 precision 时,会截掉多余的字符;当字符串的长度小于 precision 时,.precision 就不再起作用。
1
2
3
4
5
6
7
8
9
int n = 123456;
double f = 882.923672;
char *str = "abcdefghi";
// 对于 n,.precision 表示最小输出宽度。n 本身的宽度为 6,当 precision 为 9 时,大于 6,要在 n 的前面补 3 个 0;当 precision 为 4 时,小于 6,不再起作用。
printf("n: %.9d  %.4d\n", n, n); 
// 对于 f,.precision 表示输出精度。f 的小数部分有 6 位数字,当 precision 为 2 或者 4 时,都小于 6,要按照四舍五入的原则截断小数;当 precision 为 10 时,大于 6,要在小数的后面补四个 0。
printf("f: %.2lf  %.4lf  %.10lf\n", f, f, f);
// 对于 str,.precision 表示最大输出宽度。str 本身的宽度为 9,当 precision 为 5 时,小于 9,要截取 str 的前 5 个字符;当 precision 为 15 时,大于 9,不再起作用。
printf("str: %.5s  %.15s\n", str, str);
  1. flag 是标志字符。例如,%#x中 flag 对应 #,%-9d中 flags 对应-。下表列出了 printf() 可以用的 flag:
标志字符 含义
- -表示左对齐。如果没有,就按照默认的对齐方式,默认一般为右对齐。
+ 用于整数或者小数,表示输出符号(正负号)。如果没有,那么只有负数才会输出符号。
格 用于整数或者小数,输出值为正时冠以空格,为负时冠以负号。
# 对于八进制(%o)和十六进制(%x / %X)整数,# 表示在输出时添加前缀;八进制的前缀是 0,十六进制的前缀是 0x / 0X。对于小数(%f / %e / %g),# 表示强迫输出小数点。如果没有小数部分,默认是不输出小数点的,加上 # 以后,即使没有小数部分也会带上小数点。
1
2
3
4
5
6
int m = 192, n = -943;
float f = 84.342;
printf("m=%10d, m=%-10d\n", m, m);  // 演示 - 的用法, 当以%10d输出 m 时,是右对齐,所以在 192 前面补七个空格;当以%-10d输出 m 时,是左对齐,所以在 192 后面补七个空格。
printf("m=%+d, n=%+d\n", m, n);     // 演示 + 的用法, m 是正数,以%+d输出时要带上正号;n 是负数,以%+d输出时要带上负号。
printf("m=% d, n=% d\n", m, n);     // 演示空格的用法, m 是正数,以% d输出时要在前面加空格;n 是负数,以% d输出时要在前面加负号。
printf("f=%.0f, f=%#.0f\n", f, f);  // 演示#的用法, %.0f表示保留 0 位小数,也就是只输出整数部分,不输出小数部分。默认情况下,这种输出形式是不带小数点的,但是如果有了#标志,那么就要在整数的后面“硬加上”一个小数点,以和纯整数区分开。
Licensed under CC BY-NC-SA 4.0