比较两个字符串的前 count 个字符strncmp
c
static inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
int d0, d1, d2;
__asm__ __volatile__(
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
:"1" (cs),"2" (ct),"3" (count));
return __res;
}
1. 函数功能概述
这是一个用内联汇编实现的 strncmp 函数,用于比较两个字符串的前 count 个字符
2. 代码分段详解
2.1. 第一段:函数声明和变量定义
c
static inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
int d0, d1, d2;
static inline表示内联函数,调用时直接展开const char * cs第一个字符串指针const char * ct第二个字符串指针size_t count要比较的最大字符数register int __res寄存器变量存储比较结果d0, d1, d2临时变量用于汇编约束
2.2. 第二段:内联汇编开始和循环控制
c
__asm__ __volatile__(
"1:\tdecl %3\n\t"
"js 2f\n\t"
__asm__ __volatile__开始内联汇编块1:\tdecl %3标签1:递减计数器count(操作数3)js 2f如果结果为负(符号位为1),跳转到标签2(count减到-1表示比较完成)
2.3. 第三段:字符加载和比较
c
"lodsb\n\t"
"scasb\n\t"
lodsb从[esi]加载字节到al,同时esi加1(加载cs的字符)scasb比较al与[edi]的字节,同时edi加1(比较ct的字符)
2.4. 第四段:字符比较结果判断
c
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
jne 3f如果字符不相等,跳转到标签3testb %%al,%%al测试当前字符是否为0(字符串结束符)jne 1b如果不是0,跳转回标签1继续循环
2.5. 第五段:字符串相等的情况
c
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
2:\txorl %%eax,%%eax标签2:将eax清零(返回0,表示字符串相等)jmp 4f跳转到标签4(函数结束)
2.6. 第六段:字符串不相等的情况
c
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
3:\tsbbl %%eax,%%eax标签3:带借位减法,eax = eax - eax - CF- 如果
cs的字符 <ct的字符,CF=1,结果为 -1 (0xFFFFFFFF) - 如果
cs的字符 >ct的字符,CF=0,结果为 0
- 如果
orb $1,%%al将al的最低位置1- 如果原来是 -1 (0xFF),置1后还是 -1 (0xFF)
- 如果原来是 0,置1后变成 1
4:标签4:函数结束标签
2.7. 第七段:汇编约束条件
c
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
:"1" (cs),"2" (ct),"3" (count));
输出操作数:
"=a" (__res):__res绑定到eax寄存器(结果值)"=&S" (d0):d0绑定到esi寄存器(& 表示早期破坏)"=&D" (d1):d1绑定到edi寄存器"=&c" (d2):d2绑定到ecx寄存器
输入操作数:
"1" (cs):cs使用与操作数1相同的约束(esi)"2" (ct):ct使用与操作数2相同的约束(edi)"3" (count):count使用与操作数3相同的约束(ecx)
2.8. 第八段:函数返回
c
return __res;
}
- 返回比较结果
3. 函数工作流程图
是 否 不相等 相等 是0 不是0 开始strncmp count递减 count < 0? 设置eax=0
字符串相等 lodsb加载cs字符
scasb比较ct字符 字符相等? 根据CF标志设置返回值
字符为0?
字符串结束? 返回0 返回-1或1
寄存器使用说明
| 寄存器 | 用途 |
|---|---|
eax |
存储当前字符和最终结果 |
esi |
源字符串 cs 指针 |
edi |
目标字符串 ct 指针 |
ecx |
计数器 count |
4. 汇编指令详解
decl:递减操作数js:符号标志为1时跳转(结果为负)lodsb:从[esi]加载字节到al,esi++scasb:比较al与[edi],设置标志位,edi++jne:不相等时跳转testb:测试字节值xorl:异或操作(用于清零)sbbl:带借位减法orb:或操作(用于置位)
5. 返回值说明
| 返回值 | 含义 |
|---|---|
| 0 | 两个字符串在比较范围内完全相同 |
| -1 | cs 字符串小于 ct 字符串 |
| 1 | cs 字符串大于 ct 字符串 |
6.比较逻辑
- 逐字符比较:每次比较一个字符对
- 三种终止条件 :
- 达到
count限制(所有字符都相等) - 遇到不相等的字符
- 遇到字符串结束符
\0
- 达到
- 结果计算 :
- 完全相等:返回 0
- 不相等:根据字符的ASCII值差返回 -1 或 1
7. 函数功能总结
主要功能 :比较两个字符串的前 count 个字符。
特点:
- 使用内联汇编实现,效率极高
- 正确处理字符串结束符和比较长度限制
- 使用标准的字符串比较返回值约定
- 利用 x86 字符串操作指令优化性能
这个实现充分展示了如何用汇编语言高效实现字符串操作,特别适合在内核等性能关键的场景中使用