這一篇就是實現 d_printf,廢話不多說,直接上代碼。 由於 VC 的內聯彙編還是比較清晰,那就先貼 VC 版的。
#include <stdio.h>
void d_printf(const char *fmt, int n, int a[])
{
static int size1, size2;
static const char *fmt_copy;
size1 = 4*n; // 可變參數的空間大小
size2 = size1 + 4; // 還有 fmt 指針4字節, 恢復 esp 時用
fmt_copy = fmt;
__asm{
// 保護要修改的 ecx/esi/edi 寄存器
push ecx
push esi
push edi
// 給 ecx/esi/edi 賦值
mov ecx, n // movsd 的執行次數
mov esi, a // a -> esi
sub esp, size1
mov edi, esp // esp - size1 -> edi
rep movsd // n 次4字節拷貝
push fmt_copy // 壓棧格式串(字符串指針)
call printf
add esp, size2 // 恢復棧
// 恢復各個寄存器
pop edi
pop esi
pop ecx
}
}
int main()
{
char fmt[1024]; // 格式串
char c; // 額外讀取一個字符
int a[1024]; // 存讀到的整數
int i;
while(EOF != scanf("%s%c", fmt, &c)) // 讀到 EOF 就結束
{
if(c == '\n') // 格式串後沒有數字
{
printf("%s\n\n", fmt); // 直接打印, 不用 d_printf
continue;
}
// 循環讀取各個整數
i = 0;
do
{
scanf("%d%c", &a[i++], &c);
}while(c != '\n');
// 調用 d_printf, i 剛好是輸入的整數的個數
d_printf(fmt, i, a);
printf("\n\n"); // 補個換行比較好看O(∩_∩)O~
}
}
#include <stdio.h>
void d_printf(const char *fmt, int n, int a[])
{
int d0, d1, d2;
static int size1, size2;
static const char *fmt_copy;
size1 = 4*n; // 可變參數的空間大小
size2 = size1 + 4; // 還有 fmt 指針4字節, 恢復 esp 時用
fmt_copy = fmt;
asm volatile(
"subl %6, %%esp\n\t"
"movl %%esp, %%edi\n\t"
"rep ; movsl\n\t"
"pushl %3\n\t"
"call printf\n\t"
"addl %7, %%esp"
: "=&S"(d0), "=&D"(d1), "=&c"(d2)
: "m"(fmt_copy), "0"(a), "2"(n), "m"(size1), "m"(size2));
}
int main()
{
char fmt[1024]; // 格式串
char c; // 額外讀取一個字符
int a[1024]; // 存讀到的整數
int i;
while(EOF != scanf("%s%c", fmt, &c)) // 讀到 EOF 就結束
{
if(c == '\n') // 格式串後沒有數字
{
printf("%s\n\n", fmt); // 直接打印, 不用 d_printf
continue;
}
// 循環讀取各個整數
i = 0;
do
{
scanf("%d%c", &a[i++], &c);
}while(c != '\n');
// 調用 d_printf, i 剛好是輸入的整數的個數
d_printf(fmt, i, a);
printf("\n\n"); // 補個換行比較好看O(∩_∩)O~
}
}
linux 中的運行效果如下:
[lqy@localhost temp]$ ./d_printf
nospaceword
nospaceword
%X 256
100
%d+%d=%d 1 2 3
1+2=3
>%3d>%03d> 3 3
> 3>003>
>%3d>%-3d> 3 3
> 3>3 >
[lqy@localhost temp]$
最後輸入 EOF 結束:Ctrl + D(linux)、Ctrl + Z (windows)。由於轉義符是編譯時處理的,printf 是不管的, 所以\n什麼的在這裡不管用_。
d_printf 中為什麼將 size1、size2、fmt_copy 聲明為 static 變量呢?