---
# System prepended metadata

title: C 的格式化字串
tags: [C / C++]

---

# C 的格式化字串

我們輸出字串時，不一定只會是固定一堆字元，可能還會想把一些變數塞進去。那麼我們就需要在字串中加入一些記號，告訴電腦這裡需要插入變數，而那個記號稱為占位符。

在 C 語言中，我們會使用 `%` 來代表這個記號，後面會再加上一些符號，來告訴電腦要插入的變數的資料型態，以及要占多少寬度、置左還是置右、是否要補 0 之類的排版資訊。

## 資料型態

| 符號                | 說明                            |
| :------------------ | :------------------------------ |
| `%d` / `%i`         | 十進位整數                      |
| `%u`                | 無符號的十進位整數              |
| `%o`                | 無符號的八進位整數              |
| `%x` / `%X`         | 無符號的十六進位整數            |
| `%f` / `%F`         | 十進位的浮點數                  |
| `%e` / `%E`         | 用科學記號表示浮點數            |
| `%g` / `%G`         | 依照浮點數大小使用 `%f` 或 `%e` |
| `%a` / `%A` _(C99)_ | 十六進位的浮點數                |
| `%c`                | 字元                            |
| `%s`                | 字串                            |
| `%p`                | 指標的記憶體位址                |
| `%n`                | 什麼都不會輸出                  |
| `%%`                | 百分比符號(`%`)                 |

備註:

-   整數和浮點數格式化後，字母 (a-f) 的大小寫會根據符號的大小寫而定。
    如: `%x` 會輸出 `6b`，而 `%X`會輸出 `6B`。
-   `%f` 和 `%e` 會將小數點後的所有位數表示出來，即使全為 0 也會；而 `%g` 則會省略。
-   `%a` 和 `%A` 於 C99 加入
-   `%p` 只有小寫的形式，`%P` 不會轉成大寫字母，只會讓你編譯錯誤。
-   `%n` 所需傳入的參數必須是 `int` 型別的指標。
-   由於 `%` 在這裡有著特殊的意義，所以要打兩次 (`%%`) 來讓電腦知道你只是想輸出 `%`，並沒有別的意思。

### 範例 1

```c=
int a = 2042, b = -100;
printf("%%d of a: %d\n", a);
printf("%%o of a: %o\n", a);
printf("%%x of a: %x\n", a);
printf("%%X of a: %X\n", a);
printf("\n");
printf("%%d of b: %d\n", b);
printf("%%u of b: %u\n", b);
```

輸出:

```
%d of a: 2042
%o of a: 3772
%x of a: 7fa
%X of a: 7FA

%d of b: -100
%u of b: 4294967196
```

### 範例 2

```c=
double c = 395.6, d = 123465790.123;
printf("%%f of c: %f\n", c);
printf("%%e of c: %e\n", c);
printf("%%E of c: %E\n", c);
printf("%%g of c: %g\n", c);
printf("%%a of c: %a\n", c);
printf("\n");
printf("%%f of d: %f\n", d);
printf("%%e of d: %e\n", d);
printf("%%g of d: %g\n", d);
```

輸出:

```
%f of c: 395.600000
%e of c: 3.956000e+02
%E of c: 3.956000E+02
%g of c: 395.6
%a of c: 0x1.8b9999999999ap+8

%f of d: 123465790.123000
%e of d: 1.234658e+08
%g of d: 1.23466e+08
```

### 範例 3

```c=
char chr = 'C';
char str[] = "在外面%一次就好了";
printf("%c\n", chr);
printf("這裡要兩次%%，%s\n", str);
```

輸出:

```
C
這裡要兩次%，在外面%一次就好了
```

### 範例 4

```c=
int n = 1;
printf("Address: %p\n", &n);
printf("There is nothing %n.\n", &n);
```

輸出:

```
Address: 0x7ffc8a370014
There is nothing .
```

## 資料長度

有時候我們會加上一些符號，來表示資料型態的大小。例如 `%d` 加上 `ll` 後變成 `%lld`，表示`long long int` 而非 `int`。
下面是一些常用的符號:

| 長度       | `d` / `i`       | `u` / `o` / `x` / `X` | `f` / `e` / `g` / `a` | `n`              |
| :--------- | :-------------- | :-------------------- | :-------------------- | ---------------- |
| (none)     | `int`           | `unsigned int`        | `double`              | `int*`           |
| hh _(C99)_ | `signed char`   | `unsigned char`       |                       | `signed char*`   |
| h          | `short`         | `unsigned short`      |                       | `short*`         |
| l          | `long`          | `unsigned long`       | `doulbe` _(C99)_      | `long*`          |
| ll _(C99)_ | `long long`     | `unsigned long long`  |                       | `long long*`     |
| j _(C99)_  | `intmax_t`      | `uintmax_t`           |                       | `intmax_t*`      |
| z _(C99)_  | signed `size_t` | `size_t`              |                       | signed `size_t*` |
| t _(C99)_  | `ptrdiff_t`     | unsigned `ptrdiff_t`  |                       | `ptrdiff_t*`     |
| L          |                 |                       | `long doulbe`         |                  |

備註:

-   `hh`、`ll`、`j`、`z`、`t` 於 C99 加入

## 格式化

在 `%` 與表示資料型態的符號之間，還可以再加入一些東西，來指定輸出的格式。

| 符號      | 說明                                                                          |
| :-------- | :---------------------------------------------------------------------------- |
| -         | 表示靠左對齊 (預設為靠右對齊)                                                 |
| +         | 強制顯示數值的正負號 (預設只有負數會顯示)                                     |
| _(space)_ | 如果沒有顯示正負號，就用顯示空格                                              |
| #         | 如果是八進位，在數字前面加上 `0`；如果是十六進位，在數字前面加上 `0x` 或 `0X` |
| 0         | 表示在數字的左側補 0                                                          |
| _數字_    | 表示最少要顯示多少字元。長度不足的話會用空格填補；超過的話不會被截斷          |
| _.數字_   | 表示浮點數在小數點後的位數                                                    |

### 範例 1

```c=
int a = 12, b = 3465789;
printf("|%d|%+d|% d|\n", a, a, a);
printf("|%5d|%+5d|% 5d|\n", a, a, a);
printf("|%05d|%+05d|% 05d|\n", a, a, a);
printf("|%-5d|%-+5d|%- 5d|\n", a, a, a);
printf("%5d\n", b);
```

輸出:

```
|12|+12| 12|
|   12|  +12|   12|
|00012|+0012| 0012|
|12   |+12  | 12  |
3465789
```

### 範例 2

```c=
double c = 123.465789;
printf("|%3f|\n", c);
printf("|%.3f|\n", c);
printf("|%8.3f|\n", c);
printf("|%8.0f|\n", c);
printf("%#.6a\n", c);
```

輸出:

```
|123.465789|
|123.466|
| 123.466|
|     123|
0x1.eddcf8p+6
```

## 延伸閱讀

其他更詳細的內容，可以參考說明文件:

-   https://cplusplus.com/reference/cstdio/printf/
-   https://en.cppreference.com/w/c/io/fprintf
