一、printf()的简介
基于C11标准
注意:编译器:TDM-GCC 4.9.2 64-bit Rlease;long int 到底是 32bits 还是 64bits 跟生成的程序是 32bits 还是 64bits 一一对应,如果使用 g++ 编译程序的话,可通过-m32或-m64选项分别生成 32bits 和 64bits 的程序。因本人测试代码编译生成的是 32bits 的程序,所以 long int 也就是 32btis。
printf() 是C语言标准库函数,定义于头文件 <stdio.h>。
功能:按format指向的格式字符串所规定的格式,将输出表列args的值输出到标准输出设备上。即将指定数据输出到屏幕(命令提示符、显示器、控制台)上。可称之为:格式化输出函数。
1.printf()的声明
int printf(const char* format, args, ...)
2.printf()之格式控制串、输出参数表、返回值
① printf()函数根据format(格式控制串)给出的格式打印输出到stdout(标准输出)和其它参数中。
② 格式控制串:指数据输入的格式
格式控制串:格式字符+普通字符
普通字符:将原样不动地复制到标准输出
格式字符:转换说明符、标志、宽度、精度。
转换说明符和百分号[%]一起使用,来说明内存中的数据输出的格式。由%开始,以转换转换说明符结束。
format:可以是一个字符串,或是字符数组的其实地址。
③ 输出参数表:待输出的数据,可以是常量、变量或其他更复杂的表达式,也可以没有输出项。
当有多个输出项时,各输出项用逗号隔开。
输出项必须与格式字符在类型和数量上完全对应。
④ 返回值
输出字符的个数,若出错,返回负数。
二、format 转换说明组成
format 转换说明组成:
%[flags][width][.precision][length]specifier
%[标志][最小宽度][.精度][类型长度]说明符 。注意:这代表一个格式控制符。
1😲说明符(specifier)
说明符(specifier)用于规定输出数据的类型,参照表:
2😀标志(flags)
标志(flags)用于规定输出样式,含义如下:
3😲最小宽度(width)
最小宽度(width)用于控制显示字段的宽度,取值和含义如下:
4😲精度(.precision)
5😊类型长度(length)
类型长度(length)用于控制待输出数据的数据类型长度,取值和含义如下:
6😮转义序列
转义序列在字符串中会被自动转换为相应的特殊字符。printf() 使用的常见转义字符如下
三、printf()实战
1.输出格式中的普通字符
当printf()参数只有"格式控制串","格式控制串"中没有格式字符而只有普通字符时,函数完成的功能是将双引号中的字符串原样输出(显示在屏幕上)。
#include<stdio.h>
int main()
{
printf("hello C! - 你好 C");
return 0;
}
运行结果:
hello C! - 你好 C
2.输出格式中的转换字符串
转换说明符规定了对应输出项的输出类型,即将输出的数据转换为指定的格式输出。该项不能省略。格式为:
%转换说明符
2.1对有符号整数操作
#include<stdio.h>
int main()
{
short int si = 1230;
int in = 1231;
long int li = 1232;
long long int lli = 1233;
printf("对应类型字节位数: %d | %d | %d | %d\n", sizeof(short int),\
sizeof(int), sizeof(long int), sizeof(lli));
printf("si = %hd | in = %d | li = %ld | lli = %lld", si, in, li, lli);
return 0;
}
运行结果:
对应类型字节位数: 2 | 4 | 4 | 8
si = 1230 | in = 1231 | li = 1232 | lli = 1233
2.2对无符号整数操作
#include<stdio.h>
int main()
{
unsigned short int usi = 1230;
unsigned int uin = 1231;
unsigned long int uli = 1232;
unsigned long long int ulli = 1233;
printf("对应类型的字节位数: %d | %d | %d | %d\n", sizeof(usi),\
sizeof(uin), sizeof(uli), sizeof(ulli));
printf("si = %hu | in = %u | li = %lu | lli = %llu", usi, uin, uli, ulli);
return 0;
}
运行结果:
对应类型的字节位数: 2 | 4 | 4 | 8
si = 1230 | in = 1231 | li = 1232 | lli = 1233
2.3对浮点数操作
#include<stdio.h>
int main()
{
float flo = 13.14;
double dou = 52.0;
printf("对应类型字节位数: %d | %d\n", sizeof(flo), sizeof(dou));
printf("flo = %f | dou = %lf", flo, dou);
return 0;
}
运行结果:
对应类型字节位数: 4 | 8
flo = 13.140000 | dou = 52.000000
注:浮点数无符号类型同整数类型相似
2.4对字符和字符串操作
#include<stdio.h>
int main()
{
char ch = 'H';
char* str = "Hello C!";
printf("对应类型的字节位数: %d | %d\n", sizeof(ch), sizeof(str));
printf("ch = '%c' | str = \"%s\"\n", ch, str);
printf("%hhd\n", 'A'); // 输出有符号 char
printf("%hhu\n", 'A' + 128);// 输出无符号 char
return 0;
}
运行结果:
对应类型的字节位数: 1 | 8
ch = 'H' | str = "Hello C!"
65
193
2.5按八进制、十六进制输出
#include<stdio.h>
int main()
{
int in = 1024;
printf("%o | %x | %X", in, in, in, in);
return 0;
}
运行结果:
2000 | 400 | 400
2.6按科学计数法输出
#include<stdio.h>
int main()
{
double dou1 = 123456;
double dou2 = -0.123456789;
printf("%le | %lE | %le | %lE\n", dou1, dou1, dou2, dou2);
printf("%lg | %lG | %lg | %lG", dou1, dou1, dou2, dou2);
return 0;
}
结果:
1.234560e+005 | 1.234560E+005 | -1.234568e-001 | -1.234568E-001
123456 | 123456 | -0.123457 | -0.123457
2.7 %的输出、控制字符串的隐化
#include<stdio.h>
int main()
{
int in = 1314;
char *str = "%%:id(in) = %p";
printf(str, &in);
return 0;
}
运行结果:
%:id(in) = 000000000062FE14
3.输出格式中的宽度修饰符
3.1 带常量宽度的输出
#include<stdio.h>
int main()
{
int in = 1314520;
printf("%5d | %10d", in, in);
return 0;
}
运行结果:
1314520 | 1314520
3.2带变量宽度的输出
#include<stdio.h>
int main()
{
int in = 1314520;
printf("%*d | %*d | %*0d", 3, in, 10, in, 1, in);
return 0;
}
运行结果:
1314520 | 1314520 | 1314520
4.输出格式中标志、宽度修饰符
4.1指定左右对齐、显示正负号输出
#include<stdio.h>
int main()
{
int in = 1314520;
printf("%+10d | %-10d", in, in);
return 0;
}
运行结果:
+1314520 | 1314520
4.2指定空余字符用0填充
#include<stdio.h>
int main()
{
int in = 1314520;
char* str = "1314520";
printf("%.4d | %.10d\n", in, in); // %.10d 等价于 %010d
printf("%0+10d | %0-10d | %010s | %0-10s", in, in, str, str);
return 0;
}
运行结果:
1314520 | 0001314520
+001314520 | 1314520 | 0001314520 | 1314520
4.3输出格式前缀修饰符#
#include<stdio.h>
int main()
{
int in = 1024;
printf("%#o | %#X", in, in); // 带前缀八进制、十六进制输出
return 0;
}
运行结果:
02000 | 0X400
5.输出格式中精度修饰符
5.1按指定常量位数输出小数
#include<stdio.h>
int main()
{
double dou = 3.1415926;
printf("%.4lf | %.10lf", dou, dou); // 自动四舍五入
return 0;
}
运行结果:
3.1416 | 3.1415926000
注:对浮点数进行截断时,会有四舍五入。
5.2按指定变量位数输出小数
#include<stdio.h>
int main()
{
double dou = 3.1415926;
printf("%*.4lf | %*.*lf", 15, dou, 20, 10, dou); // 自动四舍五入
//变动宽度15格.常量保留小数点后4位 | 变动宽度20位.变量保留点后10位
return 0;
}
运行结果:
3.1416 | 3.1415926000
5.3 输出指定位数字符串(可以自动截断)
#include<stdio.h>
int main()
{
char str[] = "Hello C Programming!";
printf("%.10s", str);
return 0;
}
运行结果:
Hello C Pr
6.输出格式中类型长度修饰符
类型长度指明待输出数据的长度。因为相同类型可以有不同的长度,可参考下表
😲😀用于解释带和不带长度说明符的相应参数的类型(下表)
注: 黄色背景行标识的类型长度说明符和相应的数据类型是C99引入的。
参考:http://www.cplusplus.com/reference/cstdio/printf/?kw=printf
6.1 整型的不同长度类型
#include<stdio.h>
#include<limits.h>
int main()
{
short si = (1 << 15) -1;
int in = (1 << 31) -1 ;
long li = (1 << 31) -1;
long long lli = (1 << 63) -1;
printf("%hd | %d | %ld %lld\n", si, in, li, lli);
printf("%hd | %d | %ld | %lld\n", SHRT_MIN, INT_MIN, LONG_MIN,LLONG_MIN);
printf("%+hd | %+d | %+ld | %+lld", SHRT_MAX, INT_MAX, LONG_MAX,LLONG_MAX);
return 0;
}
运行结果:
32767 | 2147483647 | 2147483647 -1
-32768 | -2147483648 | -2147483648 | -9223372036854775808
+32767 | +2147483647 | +2147483647 | +9223372036854775807
6.2 浮点型的不同长度类型
#include<stdio.h>
#include<limits.h>
int main()
{
float fl = 1 << 31, flo = (1 << 30)-1+(1 << 30);
double dou = 1 << 31, doub = (1 << 30)-1+(1 << 30);
printf("%f | %lf\n", fl, dou); // 注:fl 达不到预期值 dou
printf("%f | %lf\n", flo, doub);
// printf("%f | %lf\n", FLT_MIN, DBL_MIN); // <limits.h>未预配置 FLT_MIN范围,但用此编译器预测了一下
// printf("%+f | %+lf", FLT_MAX, DBL_MAX);
return 0;
}
运行结果:
-2147483648.000000 | -2147483648.000000
2147483648.000000 | 2147483647.000000
6.3 字符和字符串的宽度
#include<stdio.h>
int main()
{
char str[] = "Hello C Programming!";
printf("%.8s | %8s", str, str); // %.8s与 %8s含义不同,%.8s可以截断指定位数字符
return 0;
}
运行结果:
Hello C | Hello C Programming!
7.输出格式中有转义字符修饰
7.1 \n的使用
#include<stdio.h>
int main()
{
char str[] = "Hello\n C Programming!"; // \n :跳到下一行
printf(str);
return 0;
}
运行结果:
Hello
C Programming!
7.2 \\和\t的使用
#include<stdio.h>
int main()
{
char str[] = "Hello\\n \t Programming!"; // \\n : 解释为 \ 加上 n
printf(str);
return 0;
}
输出结果:
Hello\n C Programming!
四、printf()缓冲
在 printf 的实现中,在调用 write 之前先写入 IO 缓冲区,这是一个用户空间的缓冲。系统调用是软中断,频繁调用,需要频繁陷入内核态,这样的效率不是很高,而 printf 实际是向用户空间的 IO 缓冲写,在满足条件的情况下才会调用 write 系统调用,减少 IO 次数,提高效率。
可参考参考文献:printf函数打印(二)—— 缓冲区篇(文件读写再探究)_printf flush-CSDN博客
五、小节
本文详细讲解了printf()的格式控制串的含义及其应用。首次在CSDN上发表文章难免会出现错误,敬请指正,不胜感激;文章内容渲染不足,样式单一,还望海涵。耗时漫长,如意完成printf()基础内容,但内容详实丰富。
本文参考文献:
printf(格式化输出函数)_百度百科 (baidu.com)
C语言printf() 详解之终极无惑_printf头文件-CSDN博客
在线工具:
C 在线工具 | 菜鸟工具 (runoob.com)https://c.runoob.com/compile/11/C库函数:文章开篇