之前在QQ群里常会看到同学们做的一个题“整数转字符串”,今天还真用上了,在拼接SQL语句的时候,用sprintf效率还低呀,就想这优化优化,首先想到的就是替换掉sprintf "%d"的部分,果然效率高了不少,然后进一步我就想到了用ASM来搞搞了:
.686
.model flat, c
option casemap:none
.code
;没有跟atoi的返回值一样返回指针,而是返回字符串长度,是为了拼接方便
i2a proc uses esi edi buff:dword, val:sdword
mov ecx, 10 ;除数
mov eax, val ;被除数
mov esi, buff ;esi指向buff的指针
cmp eax, 0 ;取绝对值
jge @f
neg eax
@@:
cdq
idiv ecx ;已经是绝对值了,IDIV/DIV都可以
add dl, '0' ;将数值变成字符
mov [esi], dl ;然后写入字符串中
inc esi
test eax, eax ;根据商决定是否继续
jnz @b
cmp sdword ptr [val],0 ;负号
jge @f
mov byte ptr [esi], '-'
inc esi
@@:
mov byte ptr[esi], 0 ;\0结尾
mov eax, esi ;返回值:字符串长度
mov edi, buff ;逆序字符串
dec esi
@@:
cmp edi, esi
jge @f
mov dl, [edi]
mov cl, [esi]
mov [edi], cl
mov [esi], dl
dec esi
inc edi
jmp @b
@@:
ret
i2a endp
end
测试结果:
#include <stdio.h>
#include <Windows.h>
#pragma warning(disable:4996)
extern "C" unsigned int i2a(const char* buff, int val);
int main()
{
char buff[128];
DWORD64 start;
char* p = NULL;
int len = 0;
char sql[1024];
//方法1
start = __rdtsc();
for(int i = 0; i < 100000; i++)
snprintf(sql, sizeof(sql), "insert into table1(gid,gname,age)values(%d,'%s',%d)", 33021, "demoname", 29);
printf("%10I64d:%s\n", __rdtsc() - start, sql);
memset(sql, 0, sizeof(sql));
//方法2
start = __rdtsc();
for (int i = 0; i < 100000; i++)
{
memcpy(sql, "insert into table1(gid,gname,age)values(", 40);
p = sql + 40;
itoa(33021, buff, 10);
len = strlen(buff);
memcpy(p, buff, len);
p += len;
memcpy(p, ",'", 2);
p += 2;
memcpy(p, "demoname", 8);
p += 8;
memcpy(p, "',", 2);
p += 2;
itoa(29, buff, 10);
len = strlen(buff);
memcpy(p, buff, len);
p += len;
memcpy(p, ")\0", 2);
}
printf("%10I64d:%s\n", __rdtsc() - start, sql);
memset(sql, 0, sizeof(sql));
//方法3
start = __rdtsc();
for (int i = 0; i < 100000; i++)
{
memcpy(sql, "insert into table1(gid,gname,age)values(", 40);
p = sql + 40;
len = i2a(buff, 33021);
memcpy(p, buff, len);
p += len;
memcpy(p, ",'", 2);
p += 2;
memcpy(p, "demoname", 8);
p += 8;
memcpy(p, "',", 2);
p += 2;
len = i2a(buff, 29);
memcpy(p, buff, len);
p += len;
memcpy(p, ")\0", 2);
}
printf("%10I64d:%s\n", __rdtsc() - start, sql);
return 0;
}
101040316:insert into table1(gid,gname,age)values(33021,'demoname',29)
10812104:insert into table1(gid,gname,age)values(33021,'demoname',29)
6176219:insert into table1(gid,gname,age)values(33021,'demoname',29)