博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言 x86_64处理器下利用gcc内联汇编实现打印char的二进制编码
阅读量:4303 次
发布时间:2019-05-27

本文共 4929 字,大约阅读时间需要 16 分钟。

由于汇编语言针对特定机器,因此给出大端/小端机器下的2种不同代码

实现思路

  1. 使用shlb依次移出每一位到CF
  2. 使用setbCF的值转移到cl
  3. rcx左移/循环右移8位,视机器不同而不同
  4. 重复上述操作8次

64位小端机器

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;}

64位大端机器

由于此类机器比较罕见,因此未做测试,仅理论上可行。

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/

你可能感兴趣的文章
docker安装 rabbitMq
查看>>
git 常用命令 入门
查看>>
linux安装docker
查看>>
关闭selinx nginx无法使用代理
查看>>
shell 脚本部署项目
查看>>
spring cloud zuul网关上传大文件
查看>>
springboot+mybatis日志显示SQL
查看>>
工作流中文乱码问题解决
查看>>
maven打包本地依赖包
查看>>
spring boot jpa 实现拦截器
查看>>
jenkins + maven+ gitlab 自动化部署
查看>>
Pull Request流程
查看>>
Lambda 表达式
查看>>
函数式数据处理(一)--流
查看>>
java 流使用
查看>>
java 用流收集数据
查看>>
java并行流
查看>>
CompletableFuture 组合式异步编程
查看>>
mysql查询某一个字段是否包含中文字符
查看>>
Java中equals和==的区别
查看>>