1. 程式人生 > >《C語言介面與實現》實驗——格式化(Fmt_T)

《C語言介面與實現》實驗——格式化(Fmt_T)

實驗程式是用vc6編譯,一定注意副檔名為c,不是cpp,下載前面幾個測試程式(連結串列、表、原子中有下載連結)中直接將下面源程式覆蓋1.c的內容即可!

再次強烈建議在這些函式上設上斷點,按F11跟進去把原始碼走一遍,才有真正的學習效果!

源程式如下:

#include <stdio.h>
#include <string.h>
#include "include/Fmt.h"
#include "include/Str.h"

#pragma comment(lib, "libcii.lib")

typedef int (*FN)(int, void *);

void main()
{
	//注意:C語言一定要將這些變數宣告放在函式的頭部
	char *s1 = NULL;


	//
	//	以下為【格式化】函式
	//
	Fmt_fmt((FN)fputc, stdout, "測試1: Fmt_fmt: %d, %s, %x, %f, %e, %g, 單字元: %c, 16進位制:0X%x\n", 9988, "OK", 9988, 90.89, 90.89, 90.89, 
		101, 101);
	/*
		下面這些函式最終會呼叫:Fmt_vfmt 
			遇到【%d】時,呼叫:cvt_d,此靜態函式已經在初始化時安裝好,見書中文版P164的cvt[]初始賦值
			'd' = 100(ASCII值),對應:cvt_d 函式
			'c' = 100,對應: cvt_c 函式
			'e' = 101,'f' = 102, 'g' = 103,三個都是浮點數轉換,下標均對應cvt_f函式,見中文版P170說明,內部都是呼叫了sprintf庫函式來格式化
			'x' = 101,,對應: cvt_x 函式,留心原始碼的“*--p = "0123456789abcdef"[m&0xf];”部分;
			.............

	*/



	//
	//
	Fmt_print("測試2: Fmt_print: %d, %s, %x\n", 9988, "OK", 9988);
	//
	Fmt_fprint(stdout, "測試3: Fmt_fprintf: %d, %s, %x\n", 9988, "OK", 9988);
	//
	s1 = Fmt_string("測試4: Fmt_string: %d, %s, %x\n", 9988, "OK", 9988);
	printf("%s", s1);


	//
	//	以下為【轉換】函式
	//
	Fmt_register('@', Str_fmt);
	/*
		'@' = 64, 關聯上 Str_fmt,Str_fmt和cvt_d,cvt_s, cvt_o,cvt_f等等是一樣的定義方式
		觀察Str_fmt的內部實現,是接受【開始偏移】和【顯示長度】兩個引數,因此僅適合下面Fmt_print的用法
		可以比較Str_fmt和cvt_s兩個函式的實現(附後)
	*/


	Fmt_print("測試5: Fmt_string: %@\n", "ChinaOKYes", 0, 4);

}

輸出
測試1: Fmt_fmt: 9988, OK, 2704, 90.890000, 9.089000e+001, 090.89, 單字元: e, 16
進位制:0X65
測試2: Fmt_print: 9988, OK, 2704
測試3: Fmt_fprintf: 9988, OK, 2704
測試4: Fmt_string: 9988, OK, 2704
測試5: Fmt_string: naOKYes
Press any key to continue

比較cvt_s(src/fmt.c),和Str_fmt(src/str.c)兩個函式:
static void cvt_s(int code, va_list *app,
	int put(int c, void *cl), void *cl,
	unsigned char flags[], int width, int precision) {
	char *str = va_arg(*app, char *);
	assert(str);
	Fmt_puts(str, strlen(str), put, cl, flags,
		width, precision);
}


void Str_fmt(int code, va_list *app,
	int put(int c, void *cl), void *cl,
	unsigned char flags[], int width, int precision) {
	char *s;
	int i, j;
	assert(app && flags);
	s = va_arg(*app, char *);
	i = va_arg(*app, int);
	j = va_arg(*app, int);
	convert(s, i, j);
	Fmt_puts(s + i, j - i, put, cl, flags,
		width, precision);
}


附:ASCII表非常有用,再附上一遍,便於檢視:

The following table lists 0 - 127.

Code Char Code Char Code Char Code Char
0 32 [space] 64 @ 96 `
1 33 ! 65 A 97 a
2 34 " 66 B 98 b
3 35 # 67 C 99 c
4 36 $ 68 D 100 d
5 37 % 69 E 101 e
6 38 & 70 F 102 f
7 39 ' 71 G 103 g
8 ** 40 ( 72 H 104 h
9 ** 41 ) 73 I 105 i
10 ** 42 * 74 J 106 j
11 43 + 75 K 107 k
12 44 , 76 L 108 l
13 ** 45 - 77 M 109 m
14 46 . 78 N 110 n
15 47 / 79 O 111 o
16 48 0 80 P 112 p
17 49 1 81 Q 113 q
18 50 2 82 R 114 r
19 51 3 83 S 115 s
20 52 4 84 T 116 t
21 53 5 85 U 117 u
22 54 6 86 V 118 v
23 55 7 87 W 119 w
24 56 8 88 X 120 x
25 57 9 89 Y 121 y
26 58 : 90 Z 122 z
27 59 ; 91 [ 123 {
28 60 < 92 \ 124 |
29 61 = 93 ] 125 }
30 - 62 > 94 ^ 126 ~
31 63 ? 95 _ 127