2015年12月11日 星期五

printf()

格式化輸出: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.ddddddd 數目
e, E[-]m.dddddde±xx 或 [-]m.ddddddE±xx d 數目
g, G較小的數使用 e 或 E,否則用 fsignificant 位數
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);
}

參考:

  1. The C Programming Language, Brian W. Kernighan & Dennis M. Ritchie
  2. man 3 printf
  3. format string attack:https://bamboofox.cs.nctu.edu.tw/uploads/material/attachment/11/format_string_exploit.pdf
  4. stdout 預設是 line buffered,換行時才會輸出。但有些方式可以馬上輸出:
    • fflush(stdout)
    • setbuf(stdout, NULL)
    • setvbuf(stdout, NULL, _IONBF, 0);

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...