前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单实现posix中规定的memcmp函数

简单实现posix中规定的memcmp函数

作者头像
灯珑LoGin
发布2022-10-31 10:27:42
6380
发布2022-10-31 10:27:42
举报
文章被收录于专栏:龙进的专栏

简介

memcmp函数的功能非常简单,传入两个指针s1和s2,以及要比较的字节大小n,比较这两块内存的值的差异(逐字节比较,把每个字节都翻译为unsigned char)。当比较第i位时,如果相等,则返回0, 否则返回不相等的字节的差值(s1i-s2i).

实现

这个问题,本来是可以无脑的写c代码来逐字节比较的。但是嘛,为了能够更高效的实现,咱们就手写汇编来做吧。

我们使用repe和cmpsb这两条指令来实现。

repz指令是一个循环指令,每次循环会不断的递减rcx寄存器内的值,当rcx为0或处理器的zero flag不为1时,退出循环。

cmpsb指令则是对两个字节作比较的指令,在计算结束后,会设置相应的状态标志位。cmpsb指令涉及到的两个操作数分别存在rdi、rsi寄存器中。在操作结束后,如果这两个操作数的值相同,则会将ZF置位。不管这两个操作数的值是否相同,都会将指针s1、s2自增1。(下面的代码已经将DF复位,因此指针是自增的)

首先,我们将处理器的zero flag给置位,假设这两块内存相等。然后把len传入rcx寄存器,一共循环len次。

然后我们使用repz;cmpsb,逐字节比较。每次比较之后,不管是否相同,s1、s2都会自增。

如果比较完所有的字节,都是相同的话,此时ZF=1. 而输出nz到diff中,因此输出的是0.

如果某一字节不相同,那么diff=1。再在下面计算这两个字节到底相差了多少,然后就出结果了。

代码语言:javascript
复制
static inline int memcmp(const void *s1, const void *s2, size_t len)
{
    int diff;

    asm("cld \n\t"  // 复位DF,确保s1、s2指针是自增的
        "repz; cmpsb\n\t" CC_SET(nz)
        : CC_OUT(nz)(diff), "+D"(s1), "+S"(s2)
        : "c"(len)
        : "memory");

    if (diff)
        diff = *(const unsigned char *)(s1 - 1) - *(const unsigned char *)(s2 - 1);

    return diff;
}

关于CC_SET和CC_OUT

可能有的小伙伴会对CC_SET和CC_OUT比较疑惑,这里将涉及的代码放出来:

CC_SET()和CC_OUT()

由于我们的编译器支持__GCC_ASM_FLAG_OUTPUTS__,因此CC_SET的工作是空的。

然后,CC_OUT就是把rflags的某一位给输出出来。上面的nz就是对ZF求反的意思。

相关链接

https://pubs.opengroup.org/onlinepubs/9699919799/functions/memcmp.html

转载请注明来源:https://longjin666.cn/?p=1572

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 实现
  • 关于CC_SET和CC_OUT
  • 相关链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档