《C语言printf函数的高级用法》阅读
头文件
printf
来自C语言头文件 stdio.h(标准IO),是C语言常用来打印日志的API。
#include <stdio.h>
cout
则来自 C++ 头文件 iostream
#include <iostream>
格式化参数
使用 printf 的一个难点就是掌握格式化参数。
通常来说,格式化参数所表示的类型与变量的实际类型一致,才能打印出正确的结果。,比如
- 声明一个 int 变量,就用 %d 来格式化该变量的值。
- 声明一个 unsigned int 变量,就用 %u 来格式化该变量的值。
以下测试环境为
- Windows 操作系统
- Visual Studio
- Win32 项目
1. 打印字符串(常用)
在C语言中,我们常用 char数组表示字符串:
#include <stdio.h>
int main() {
char str[] = "Hello";
printf("%s
", str);
return 0;
}
2. 打印整数(常用)
《C语言的整数类型》 阅读
- %d 十进制有符号整数
- %u 十进制无符号整数
C语言中,带符号的标准整数类型有 char,short,int,long,long long。
1、用%d格式化范围内的正整数:
char c = 97;
short s = 128;
int i = 1024;
long l = 65500;
long long ll = 131070;
printf("%d
", c); // 输出97
printf("%u
", c); // 输出97
printf("%d
", s); // 输出128
printf("%u
", s); // 输出128
printf("%d
", i); // 输出1024
printf("%u
", i); // 输出1024
printf("%d
", l); // 输出65500
printf("%u
", l); // 输出65500
printf("%d
", ll); // 输出131070
printf("%u
", ll); // 输出131070
2、用%d格式化超出范围的正整数:
char c = 128; // char范围是 -128~127
short s = 32768; // short范围是 -32768~32767
int i = 2147483648; // int范围是 -2147483648~2147483647
long l = 2147483648;// long范围是 -2147483648~2147483647
long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%d
", c); // 输出-128
printf("%u
", c); // 输出4294967168
printf("%d
", s); // 输出-32768
printf("%u
", s); // 输出4294934528
printf("%d
", i); // 输出-2147483648
printf("%u
", i); // 输出2147483648
printf("%d
", l); // 输出-2147483648
printf("%u
", l); // 输出2147483648
printf("%d
", ll); // 输出0
printf("%u
", ll); // 输出0
- char的长度为1个字节,128 用1个字节表示等于 0x80,被解释为有符号十进制整数 -128,因此 %d 格式化后输出 -128;
- short的长度为2个字节,32768 用2个字节表示等于 0x8000,被解释为有符号十进制整数 -32768,因此 %d 格式化后输出 -32768;
- int和long的长度为4个字节,2147483648 用4个字节表示等于 0x80000000,被解释为有符号十进制整数 -2147483648,因此 %d 格式化后输出 -2147483648;
上述的几种情况,我们在定义的时候,可以采用无符号数来声明整型变量:
unsigned char c = 128; // char范围是 -128~127
unsigned short s = 32768; // short范围是 -32768~32767
unsigned int i = 2147483648; // int范围是 -2147483648~2147483647
unsigned long l = 2147483648;// long范围是 -2147483648~2147483647
printf("%d
", c); // 输出128
printf("%u
", c); // 输出128
printf("%d
", s); // 输出32768
printf("%u
", s); // 输出32768
printf("%d
", i); // 输出-2147483648
printf("%u
", i); // 输出2147483648
printf("%d
", l); // 输出-2147483648
printf("%u
", l); // 输出2147483648
- 我们发现int和long在格式化为%d和%u时还是有所不同。
为了解决 long long 类型 printf 打印结果为 0 的问题,引入了格式化参数 %lld 和 %llu ,可以表示 64位(8字节)的整型数。
long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%lld
", ll); // 输出-9223372036854775808
printf("%llu
", ll); // 输出9223372036854775808
3、可以在“%”和字母之间插进数字表示最小宽度
%3d
中,d表示以十进制输出,3表示最少占3个字符的宽度,宽度不足以空格补齐,默认右对齐。综合起来,%3d
表示以十进制输出,右对齐,宽度最小为3个字符。
char c = 1; // char范围是 -128~127
short s = 1; // short范围是 -32768~32767
int i = 1; // int范围是 -2147483648~2147483647
long l = 1;// long范围是 -2147483648~2147483647
printf("%3d
", c);
printf("%5d
", s);
printf("%10d
", i);
printf("%10d
", l);
printf("%3d
", -c);
printf("%5d
", -s);
printf("%10d
", -i);
printf("%10d
", -l);
输出结果如下图:
还可以用 %03d 表示输出3位整型数,宽度不够3位,左边补0 :
char c = 1;
short s = 1;
int i = 1;
long l = 1;
printf("%03d
", c);
printf("%05d
", s);
printf("%010d
", i);
printf("%010d
", l);
printf("%03d
", -c);
printf("%05d
", -s);
printf("%010d
", -i);
printf("%010d
", -l);
输出结果如图所示:
我们再来看一下,超出最小宽度的情况:
char c = -127;
short s = -32767;
int i = -2147483647;
long l = -2147483647;
printf("%03d
", c);
printf("%05d
", s);
printf("%010d
", i);
printf("%010d
", l);
printf("%03d
", -c);
printf("%05d
", -s);
printf("%010d
", -i);
printf("%010d
", -l);
如图所示,负号也占一个字符位:
刚才看的是右对齐,现在再来看一下左对齐
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a1=20, a2=345, a3=700, a4=22;
int b1=56720, b2=9999, b3=20098, b4=2;
int c1=233, c2=205, c3=1, c4=6666;
int d1=34, d2=0, d3=23, d4=23006783;
printf("%-9d %-9d %-9d %-9d
", a1, a2, a3, a4);
printf("%-9d %-9d %-9d %-9d
", b1, b2, b3, b4);
printf("%-9d %-9d %-9d %-9d
", c1, c2, c3, c4);
printf("%-9d %-9d %-9d %-9d
", d1, d2, d3, d4);
system("pause");
return 0;
}
输出结果如图所示:
3. 打印16进制数
-
%o 无符号以八进制表示的整数; 八进制我们在编程时用得不多,再次就不展示了。
-
%x, %X 无符号以十六进制表示的整数(常用,打印指针一般会用到这个)
%x 表示字母小写,%X 表示字母大写
unsigned char c = 128; // char范围是 -128~127
unsigned short s = 32768; // short范围是 -32768~32767
unsigned int i = 2147483648; // int范围是 -2147483648~2147483647
unsigned long l = 2147483648;// long范围是 -2147483648~2147483647
long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%x
", c); // 输出80
printf("%x
", s); // 输出8000
printf("%x
", i); // 输出80000000
printf("%x
", l); // 输出80000000
printf("%llx
", ll); // 输出8000000000000000
-
注意使用 %x 格式化超过32位所能表示的值时,会输出0。因此,需要改用 %llx 格式化64位的整型;
-
如果打印16进制数时需要
0x
前缀,可以选用格式化参数%#x
。
4. 打印浮点数
- %f 浮点数
- %e 指数形式的浮点数
float f = 3.4028235E38; // float 的范围是 [-3.4028235E38, 3.4028235E38]
double d = 3.4028235E50;
printf("%f
", f); // 输出 340282346638528860000000000000000000000.000000
printf("%e
", f); // 输出 3.402823e+038
printf("%f
", d); // 输出 340282350000000000000000000000000000000000000000000.000000
printf("%e
", d); // 输出 3.402824e+050
printf("%lf
", d); // 输出 340282350000000000000000000000000000000000000000000.000000
打印浮点数时,常常要求保留精度:
float f = 3.4028235E38; // float 的范围是 [-3.4028235E38, 3.4028235E38]
double d = 3.4028235E50;
printf("%.2f
", f); // 输出 340282346638528860000000000000000000000.00
printf("%.2e
", f); // 输出 3.40e+038
printf("%.3f
", d); // 输出 340282350000000000000000000000000000000000000000000.000
printf("%.3e
", d); // 输出 3.403e+050
printf("%.1lf
", d); // 输出 340282350000000000000000000000000000000000000000000.0
5. 打印单个字符
%c 单个字符(常用)
char a = 'a';
int b = 98;
printf("%c
", a); // 输出a
printf("%c
", b); // 输出b
6. 打印指针
%p 指针
char str[] = {'G', 'o', 'd', ' '};
printf("%p", str); // 在一次实验中,输出00F3FBCC
printf("%p
", &str); // 在一次实验中,输出00F3FBCC
printf("%c
", *str); // 输出G
如下图所示:
其中,0x00F3FBCC 是指针的首地址。对应的内存地址为:
自定义日志输出
/*=================================
* 自定义打印输出
==================================*/
#define INFO_OUTPUT 3
#define WARNING_OUTPUT 2
#define DEBUG_OUTPUT 1
#define ERROR_OUTPUT 0
#define DEBUG
#define DEBUG_LEVEL INFO_OUTPUT
#define PRINT(info, ...) do{
printf("[Info] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
}while(0)
#define INFO_PRINT(info, ...) do{
if(DEBUG_LEVEL>=INFO_OUTPUT){
printf("[Info] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
}
}while(0)
#define WARNING_PRINT(info, ...) do{
if(DEBUG_LEVEL>=WARNING_OUTPUT){
printf("[Warning] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
}
}while(0)
#define DEBUG_PRINT(info,...) do{
if(DEBUG_LEVEL>=DEBUG_OUTPUT){
printf("[Debug] (%s:%d->%s):" info"",__FILE__,__FUNCTION__,__LINE__,##__VA_ARGS__);
}
}while(0)
#define ERROR_PRINT(info, ...) do{
if(DEBUG_LEVEL>=ERROR_OUTPUT){
printf("[Error] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
}
}while(0)