本文共 4929 字,大约阅读时间需要 16 分钟。
由于汇编语言针对特定机器,因此给出大端/小端机器下的2种不同代码
shlb
依次移出每一位到CF
setb
将CF
的值转移到cl
rcx
左移/循环右移8位,视机器不同而不同char* chr2bin(uint8_t ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; uint64_t a; asm( "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" : "=c"(a) : "a"(ch) ); *(uint64_t*)buf = a + 0x3030303030303030; return buf;}
以下方法也可行,但用时略长。测试346.2MB
文件时,该方案比上面的方案用时长约30ms
。
char* chr2bin(uint8_t ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; uint64_t a; asm( "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tbswap %0" : "=c"(a) : "a"(ch) ); *(uint64_t*)buf = a + 0x3030303030303030; return buf;}
由于此类机器比较罕见,因此未做测试,仅理论上可行。
char* chr2bin(uint8_t ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; uint64_t a; asm( "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\tshlq $8, %0\n\t" "shlb %1\n\tsetb %%cl" : "=c"(a) : "a"(ch) ); *(uint64_t*)buf = a + 0x3030303030303030; return buf;}
#include#include #include char* chr2bin(uint8_t ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; uint64_t a; asm( "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" : "=c"(a) : "a"(ch) ); *(uint64_t*)buf = a + 0x3030303030303030; return buf;}int main() { char a = 0x56; char buf[8*sizeof(char) + 1]; puts(chr2bin(a, buf)); return 0;}
输出如下
01010110
可见达到目的。
传统方法使用移位判断。具体函数如下
char* print_bin(char ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; for(char i = 0; i < 8; i++) buf[i] = (ch & (128 >> i))?'1':'0'; return buf;}
读取一个346.2MB
的大文件,对2种方法分别进行测试。测试所用代码如下
#include#include #include #include char* chr2bin(uint8_t ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; uint64_t a; asm( "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" "shlb %1\n\tsetb %%cl\n\trorq $8, %0\n\t" : "=c"(a) : "a"(ch) ); *(uint64_t*)buf = a + 0x3030303030303030; return buf;}char* print_bin(char ch, char buf[8*sizeof(char) + 1]) { buf[8*sizeof(char)] = 0; for(char i = 0; i < 8; i++) buf[i] = (ch & (128 >> i))?'1':'0'; return buf;}unsigned long get_start_ms() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);}char data[65536];int main(int argc, char** argv) { FILE *fp = NULL; int cnt = 0; char buf[8*sizeof(char) + 1]; fp = fopen(argv[1], "rb"); if(!fp){ fputs("Read file error!", stderr); return 1; } //预加载,防止中断延时 while((cnt = fread(data, 1, 65536, fp))); rewind(fp); puts("开始测试..."); unsigned long t = get_start_ms(); while((cnt = fread(data, 1, 65536, fp))){ for(int ch = 0; ch < cnt; ch++) chr2bin(data[ch], buf); } printf("内联汇编用时%lums\n", get_start_ms() - t); rewind(fp); t = get_start_ms(); while((cnt = fread(data, 1, 65536, fp))){ for(int ch = 0; ch < cnt; ch++) print_bin(data[ch], buf); } printf("传统方法用时%lums\n", get_start_ms() - t); return 0;}
使用clang -O0
参数编译,运行结果如下
开始测试...内联汇编用时1941ms传统方法用时6064ms
显然,内联汇编实现的代码执行速度更快,用时约为传统方法的1/3
。理论上使用向量指令集SSE/AVX
等或使用GPU
还可获得更大的加速,在此就不做展开了。
转载地址:http://dhmws.baihongyu.com/