《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\n", 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\n", c); // 輸出97
printf("%u\n", c); // 輸出97
printf("%d\n", s); // 輸出128
printf("%u\n", s); // 輸出128
printf("%d\n", i); // 輸出1024
printf("%u\n", i); // 輸出1024
printf("%d\n", l); // 輸出65500
printf("%u\n", l); // 輸出65500
printf("%d\n", ll); // 輸出131070
printf("%u\n", 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\n", c); // 輸出-128
printf("%u\n", c); // 輸出4294967168
printf("%d\n", s); // 輸出-32768
printf("%u\n", s); // 輸出4294934528
printf("%d\n", i); // 輸出-2147483648
printf("%u\n", i); // 輸出2147483648
printf("%d\n", l); // 輸出-2147483648
printf("%u\n", l); // 輸出2147483648
printf("%d\n", ll); // 輸出0
printf("%u\n", 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\n", c); // 輸出128
printf("%u\n", c); // 輸出128
printf("%d\n", s); // 輸出32768
printf("%u\n", s); // 輸出32768
printf("%d\n", i); // 輸出-2147483648
printf("%u\n", i); // 輸出2147483648
printf("%d\n", l); // 輸出-2147483648
printf("%u\n", l); // 輸出2147483648
- 我們發現int和long在格式化為%d和%u時還是有所不同。
為了解決 long long 類型 printf 列印結果為 0 的問題,引入了格式化參數 %lld 和 %llu ,可以表示 64位(8位元組)的整型數。
long long ll = 9223372036854775808; // long long 範圍 -9223372036854775808~9223372036854775807
printf("%lld\n", ll); // 輸出-9223372036854775808
printf("%llu\n", 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\n", c);
printf("%5d\n", s);
printf("%10d\n", i);
printf("%10d\n", l);
printf("%3d\n", -c);
printf("%5d\n", -s);
printf("%10d\n", -i);
printf("%10d\n", -l);
輸出結果如下圖:

還可以用 %03d 表示輸出3位整型數,寬度不夠3位,左邊補0 :
char c = 1;
short s = 1;
int i = 1;
long l = 1;
printf("%03d\n", c);
printf("%05d\n", s);
printf("%010d\n", i);
printf("%010d\n", l);
printf("%03d\n", -c);
printf("%05d\n", -s);
printf("%010d\n", -i);
printf("%010d\n", -l);
輸出結果如圖所示:
我們再來看一下,超出最小寬度的情況:
char c = -127;
short s = -32767;
int i = -2147483647;
long l = -2147483647;
printf("%03d\n", c);
printf("%05d\n", s);
printf("%010d\n", i);
printf("%010d\n", l);
printf("%03d\n", -c);
printf("%05d\n", -s);
printf("%010d\n", -i);
printf("%010d\n", -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\n", a1, a2, a3, a4);
printf("%-9d %-9d %-9d %-9d\n", b1, b2, b3, b4);
printf("%-9d %-9d %-9d %-9d\n", c1, c2, c3, c4);
printf("%-9d %-9d %-9d %-9d\n", 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\n", c); // 輸出80
printf("%x\n", s); // 輸出8000
printf("%x\n", i); // 輸出80000000
printf("%x\n", l); // 輸出80000000
printf("%llx\n", 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\n", f); // 輸出 340282346638528860000000000000000000000.000000
printf("%e\n", f); // 輸出 3.402823e+038
printf("%f\n", d); // 輸出 340282350000000000000000000000000000000000000000000.000000
printf("%e\n", d); // 輸出 3.402824e+050
printf("%lf\n", d); // 輸出 340282350000000000000000000000000000000000000000000.000000
列印浮點數時,常常要求保留精度:
float f = 3.4028235E38; // float 的範圍是 [-3.4028235E38, 3.4028235E38]
double d = 3.4028235E50;
printf("%.2f\n", f); // 輸出 340282346638528860000000000000000000000.00
printf("%.2e\n", f); // 輸出 3.40e+038
printf("%.3f\n", d); // 輸出 340282350000000000000000000000000000000000000000000.000
printf("%.3e\n", d); // 輸出 3.403e+050
printf("%.1lf\n", d); // 輸出 340282350000000000000000000000000000000000000000000.0
5. 列印單個字元
%c 單個字元(常用)
char a = 'a';
int b = 98;
printf("%c\n", a); // 輸出a
printf("%c\n", b); // 輸出b
6. 列印指針
%p 指針
char str[] = {'G', 'o', 'd', '\0'};
printf("%p", str); // 在一次實驗中,輸出00F3FBCC
printf("%p\n", &str); // 在一次實驗中,輸出00F3FBCC
printf("%c\n", *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)