格式化輸出:printf() 這類函數有一個 format 參數用來表示輸出的字串格式。
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int dprintf(int fd, const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...); int asprintf(char **strp, const char *format, ...); #include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vdprintf(int fd, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); int vasprintf(char **strp, const char *format, va_list ap);
成功回傳打算寫入的字串長度,失敗回傳負值。如果 snprintf() 和 vsnprintf() 回傳值 ≥ size,表示有截短。glibc 從 v2.1 開始符合以上 C99 標準,之前截短回傳 -1。
基本型是 printf 輸出到 stdout,前面加
- f:列印到 FILE。
- d:列印到 fd。
- s:列印到 str 字串暫存區。
- sn:列印到 str 字串暫存區,含結尾 0 最多寫入長度 size。
- as:列印到自動配置的字串暫存區,從提供的 strp 回傳。最後不用需 free(*strp) 釋出。
- v:參數採用 va_list。
format 格式字串
| 格式字串內容 | printf() 系列 | scanf() 系列 |
|---|---|---|
| % 開頭的轉換規範 | printf() | scanf() |
空白字元集 (space、tab、newline 等) | 直接輸出 | 比對 0 個以上的空白字元集 |
| 一般字元 | 直接比對 |
輸出格式由 format 字串決定,包含兩種物件 -- 直接輸出的一般字元、以及轉換規範。每個轉換規範 (conversion specification) 通常轉換一個參數,格式:
%[flags][最小寬度][.精確度][資料類型]轉換字元
對 % 開始到轉換字元,中央會使有 flags、width (最小寬度)、precision (精確度)、和 length (資料類型)。其中最小寬度和精確度是「非 0」的數字,或用「*」來取用下個參數 (須為數字)。預設按照順序每個「*」及轉換字元取用一個參數。UNIX 規範也可以用「%m$」和「*m$」來取代 % 和 *,明確指定使用第 m 個參數,但 C99 標準不支援。如果有用 $,所有需要取用參數的都要用,且使用的參數不能有 gap。
轉換字元 (conversion specifier)
| 字元 | 輸出 | . 精確度 |
|---|---|---|
| d, i | 有號十進位 | 位數 |
| u | 無號十進位 | 位數 |
| o | 無號八進位 | 位數 |
| x, X | 無號十六進位 | 位數 |
| c | 字元 | |
| s | 字串 | 最長長度 |
| f, F | [-]mmm.dddddd | d 數目 |
| e, E | [-]m.dddddde±xx 或 [-]m.ddddddE±xx | d 數目 |
| g, G | 較小的數使用 e 或 E,否則用 f | significant 位數 |
| p | 指標值 | |
| n | 目前為止輸出的字數 | |
| % | 印「%」 |
flags
- -:向左對齊
- +:數字都印 +- 符號
- 空白字元:如果要印的第一個字元不是符號,多插入一個空白字元。
- 0:數字前面補 0。
- #:數字轉換成 alternate form,可看出是幾進位或是不是浮點。
- o:前置 0
- x 或 X:前置 0x 或 0X
- e、E、f、g、或 G 保留小數點
- g 或 G:保留小數點,且不移除尾部的 0。
- ':十進位轉換 (i, d, u, f, F, g, G) 輸出,每千位依據 locale 隔開 (見 setlocale())。
- I:十進位轉換 (i, d, u) 輸出使用 locale 語文。
資料類型 (length modifier) 指示對應的參數
- hh:signed char 或 unsigned char
- h:short 或 unsigned short
- l:long 或 unsigned long
- ll:long long 或 unsigned long long
- L:long double
- j:intmax_t 或 uintmax_t
- z:size_t 或 ssize_t
- t:ptrdiff_t
void printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
參考:
- The C Programming Language, Brian W. Kernighan & Dennis M. Ritchie
- man 3 printf
- format string attack:https://bamboofox.cs.nctu.edu.tw/uploads/material/attachment/11/format_string_exploit.pdf
- stdout 預設是 line buffered,換行時才會輸出。但有些方式可以馬上輸出:
- fflush(stdout)
- setbuf(stdout, NULL)
- setvbuf(stdout, NULL, _IONBF, 0);
沒有留言:
張貼留言