http://sunxiunan.com/?p=1640

我们将代码稍作修改,让一些宏定义变成函数更容易理解一些:

#include "stdafx.h"
#include <stdio.h>
/* fast strcpy -- Copyright (C) 2003 Thomas M. Ogrisegg <tom@hi-tek.fnord.at> */
//#include <string.h>
//#include "dietfeatures.h"
//#include "dietstring.h"
// ----following are dietstring.h content.
//#include <endian.h>
//# define MKW(x) (x|x<<8|x<<16|x<<24)
int MKW(int x)
{
x = x | x<<8 | x << 16 | x << 24;
return x;
}//# define STRALIGN(x) (((unsigned long)x&3)?4-((unsigned long)x&3):0)
unsigned long STRALIGN(unsigned long xPtr)
{
unsigned long xRet = (unsigned long)xPtr & 3;
if (xRet)
xRet = 4 - ((unsigned long) xPtr & 3);
else
xRet = 0;
return xRet;
}/* GFC(x) - returns first character */
/* INCSTR(x) - moves to next character */
# define GFC(x) ((x)&0xff)
# define INCSTR(x) do { x >>= 8; } while (0)//#define UNALIGNED(x,y) (((unsigned long)x & (sizeof (unsigned long)-1)) ^ ((unsigned long)y & (sizeof (unsigned long)-1)))
unsigned long MyUnaligned(unsigned long xPtr, unsigned long yPtr)
{
unsigned long valN1 = sizeof (unsigned long)-1;
unsigned long xVal = (unsigned long) xPtr & valN1;
unsigned long yVal = (unsigned long) yPtr & valN1;
unsigned long retVal = xVal ^ yVal;
return retVal;
}
// ----above are dietstring.h content.char *
strcpy2 (char *s1, const char *s2)
{char *res = s1;int tmp;unsigned long l;if (MyUnaligned((unsigned long)s1, (unsigned long)s2)){
while ((*s1++ = *s2++));
return (res);}if ((tmp = STRALIGN((unsigned long)s1))){
while (tmp-- && (*s1++ = *s2++));
if (tmp != -1) return (res);}while (1) {
unsigned long key1 = MKW(0x1ul);
unsigned long key2 = MKW(0x80ul);l = *(const unsigned long *) s2;if (((l - key1) & ~l) & key2) {
while ((*s1++ = GFC(l))) INCSTR(l);
return (res);
}*(unsigned long *) s1 = l;
s2 += sizeof(unsigned long);
s1 += sizeof(unsigned long);
}
}int _tmain(int argc, _TCHAR* argv[])
{
char* p = (char*)malloc(50* sizeof p);
char* str = "aaaabbbbbcccccc";
strcpy2(p, str);
free(p);
return 0;
}

为了不和标准库的strcpy名字冲突,我将其改为strcpy2.

如果你把上面的程序编译运行一下就会发现,快的原因在于strcpy2这个函数最后一部分while循环里面的这几行:

 *(unsigned long *) s1 = l;

s2 += sizeof(unsigned long);

s1 += sizeof(unsigned long);

对C语言指针了解的朋友都知道,第一行是把l这个unsigned long类型变量值赋值给s1为地址的一个unsigned long型指针指向的内容。

在我的i386cpu PC机上,第二第三行分别是将s2以及s1指针增加了4(而不是通常函数实现里面的++)。这也就实现了每次拷贝4个char(也就是一个unsigned long)而不是只拷贝一个char。

而strcpy2前面的函数就是确保这个拷贝可以正确执行。

我们先看MyUnaligned这个函数(在dietlibc中原为UNALIGNED宏)。

先取了一个值是sizeof(unsigned long) – 1,然后将源字符串指针以及目标字符串指针都与这个值做与操作(xPtr & valN1),最后两个结果做一个异或xor操作(xVal ^ yVal)。

其实说白了很简单,xPtr & valN1相当于一个取模操作,i386 cpu上valN1的值为3,也就是与的结果可能为0,1,2,3,当xPtr或者yPtr的值为4的倍数时候,与操作得到结果为0。两个与操作结果做一下异或,只有都为0或者都为1的时候,返回为0。也就是只要有一个指针没对齐,就老老实实的做一个个char的拷贝(*s1++ = *s2++),然后从strcpy2返回。

这个算法就是为了保证xPtr以及yPtr指针都是在内存上是对齐的(aligned),如果没有对齐还要一次赋值4个char,那可能导致写入内存出错(参考这篇http://en.wikipedia.org/wiki/Data_structure_alignment)。

有的同学已经看出来了,如果源指针目标指针都没对齐,xor结果也是零,那不就错了么?

OK,不还有一段代码么,在STRALIGN里面,会对目标字符串指针地址取模,然后将余数返回,比如我们运行时人为地修改s1以及s2地址将其+1。debug运行如下图,得到p以及str地址,可以看到都是对齐在unsigned long边界上的( p & 3 一定是0)。

我们在Autos窗口里直接修改地址,让其加一,如下图:

这样两个指针就都没有对齐了。继续运行:

果然如我们预计的retVal的值为0。

xRet返回值为4 – 1,也就是3。

3个字符串(“aaa”)被拷贝到目标字符串里面,这时候目标字符串指针位置是对齐的了。

这是如果有编程经验的朋友可能已经有疑问,开头有可能没对齐,也有可能结尾部分没对齐啊,也就是尾巴部分一定是4的倍数么?未必,这时候这一段代码就起作用了。

unsigned long key1 = MKW(0x1ul);

unsigned long key2 = MKW(0x80ul);

运算结果key1是0×01010101,key2结果是0×80808080,如果你看过Tony Bai写的strlen源码分析http://bigwhite.blogbus.com/logs/37753065.html ,就会发现这两个有意思的数字同样出现在glibc标准库当中。

((l – key1) & ~l) & key2我就不分析了,可以猜测到,这是对源字符串中NULL结尾符的检测。当检测到有结尾符的时候,就做按char拷贝,然后返回。感兴趣的可以参考TonyBai那篇文章,然后自己写几个test case测试一下。

整个函数就是这样,分析完毕。

转载于:https://www.cnblogs.com/lua5/archive/2010/12/09/1901591.html

dietlibc中的strcpy算法浅析相关推荐

  1. 卡尔曼滤波器求速度matlab,卡尔曼滤波器算法浅析及matlab实战

    原标题:卡尔曼滤波器算法浅析及matlab实战 作者:Liu_LongPo 出处:Liu_LongPo的博客 卡尔曼滤波器是一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的 ...

  2. SIFT(尺度不变特征变换)算法浅析

    SIFT(尺度不变特征变换)算法浅析 SIFT简介 SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种算法,这是一种 ...

  3. Paxos 算法浅析

    Paxos 算法浅析  xiewen 关注 2016.07.19 17:24* 字数 3613 阅读 3740评论 0喜欢 22 持续更新 如何浅显易懂地解说 Paxos 的算法? 参考资料 #8:知 ...

  4. 链中自有黄金屋--NFT浅析

    链中自有黄金屋–NFT浅析 前言 ​ 2021年3月11日,佳士得历史上首次拍卖以 NFT 形式展现的纯数字艺术品,这幅底价100美元的作品最终以6934.6万美元成交,一举成为在世艺术家成交作品第三 ...

  5. 深度学习中的优化算法之BGD

    之前在https://blog.csdn.net/fengbingchun/article/details/75351323 介绍过梯度下降,常见的梯度下降有三种形式:BGD.SGD.MBGD,它们的 ...

  6. php查找二维数组下标,PHP实现二维数组中的查找算法小结

    本文实例讲述了PHP实现二维数组中的查找算法.分享给大家供大家参考,具体如下: 方法1:silu从左下角最后一行的第一个元素开始,遍历.如果小于target 则遍历该行的所有元素,找到结束.如果大于继 ...

  7. Java虚拟机规范阅读(二)IEEE754简介以及Java虚拟机中的浮点算法

    什么是浮点数 在计算机系统的发展过程中,曾经提出过多种方法表达实数.典型的比如相对于浮点数的定点数(Fixed Point Number).在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置 ...

  8. 深度学习中的优化算法串讲

    Datawhale原创 作者:谢文睿,Datawhale成员 寄语:优化算法是一个超参数,一个优化算法不是适合所有损失函数的,没有哪个优化算法是绝对的好或绝对的坏,是要根据损失函数判断的 本文对深度学 ...

  9. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

最新文章

  1. MySQL数据库中文模糊检索问题
  2. C6678-SRIO和FPGA的通信
  3. python hash
  4. VTK:结构化网格之VisualizeStructuredGridCells
  5. Linux搜索无线网络命令,Linux操作系统的无线网络命令
  6. 次时代各制作插件使用方案以及技巧 包括UV 烘焙 减面等
  7. java8安装_科学网—Java JDK 8 的安装以及环境变量的配置(Linux and Windows) - 彭勇的博文...
  8. Zend_Form 创建、校验和解析表单的基础--(手冊)
  9. Sakurairo开源WordPress主题模板
  10. android华为虚拟截屏黑屏,Android截屏表面视图显示黑屏
  11. window 下tomcat 内存设置,bat启动方式的
  12. Linux时间操作(time、gettimeofday)
  13. 递归算法经典实例python-Python递归算法详解
  14. 你肯定不知道的设计心理学原则和定律
  15. 入手域名的渠道介绍!
  16. 微信小程序与servlet交互
  17. 【SpringCloud-学习笔记】Docker基本操作
  18. Excel怎么一次性删除数据末尾的空格
  19. GC策略笔记备忘(被namenode所迫)
  20. 传奇玩家访问网站自动弹窗加QQ群方法以及详细代码

热门文章

  1. php中extends是什么意思,在php中extends与implements的区别
  2. python保存数据_Python 保存数据的方法(4种方法)
  3. priorityqueue 的 add和offer方法有区别吗_日常在家安吉白茶应该如何去保存?城市与农村存放的方法有区别吗...
  4. 英特尔cpu发布时间表_10纳米来了:英特尔十一代酷睿,性能升20%,AI算力乘5倍...
  5. html 实现表格控制器,HTML 表格类 - CodeIgniter 2.x 用户手册
  6. 浏览器内存不足导致页面崩溃_深度精读:浏览器渲染原理 [8000字图文并茂]
  7. python中的os abort_Python::OS 模块 -- 进程管理
  8. html+单选+回显,VUE+elementUI表格多选框实现单选以及数据回显时toggleRowSelection失效问题...
  9. angular routerlink传递参数_[翻译]在 Angular 中使用 async-await 特性
  10. 【工作分解法】IT人,你的工作“轻松”么?