这一篇就是实现 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 变量呢?