memset 的实现分析

  • 时间:
  • 浏览:1

  下面给出的是 _VEC_memzero 的汇编代码:

  一种生活生活状况的汇编代码比较简单,但会 忽略。根据一种生活生活点里能 都看,不论在代码风格层面还是运行效率层面,认为使用初始化列表优于 memset 都在一种生活生活毫无理由的主观臆测。事实上,两者在运行效率上等效,且代码风格上不指在优劣之分。全都 ,当线程员对行态体,数组进行初始化时,那么在这里产生犹豫。底下当我门当我门后该 都看,对数组用循环的最好的办法 初始化,和调用 memset 初始化,在多数条件下的等效性。

  而认为如下使用 memset 的写法不明就里的被其排斥和拒绝:

  int a[60 ] = { 1, 2 };

  但会 ,假设有有三个整数数组 a[],可能把所有元素赋值为 0,里能 用 memset (a, 0, sizeof ( a )); // 这可能是 memset 使用中最常见的状况

  这里分析 memset 一种生活生活函数在汇编语言层面的实现最好的办法 。首先,memset 的原型如下:

  【补充】在讨论事先 ,里能 先明确有三个基本常识,即 memset 中提供的那个填充值的参数,是以字节为单位填充内存,但会 实际的 memset 补救中只把它当作字节补救(即那么 0-7 bit 重要,高位被忽略),将其低位字节扩展成 32 位(类似于参数值为 0x12345678,则实际被扩展成 0x78787878),但会 用 rep stosd 填充。但会 memset 那么像循环赋值一样,完成对内存完成 4 bytes 为周期的周期性填充(而那么把所有字节都赋值为相同值),但汇编语言里能 。

  -- hoodlum1960 on 2014年6月19日 补充。

  底下的代码相对简单,这里就不完全解释了。里能 都看有有三个名为 _VEC_memset 的标签(是有三个具体函数)在满足条件时接管了此函数。即当同時 满足:(1)_Val 为 0;(2) CPU 支持 SSE2,(3)_Size 达到某个阈值(这里是256字节)时,memset 可能跳转到 _VEC_memzero 分支。

  memset 是 msvcrt.dll (一种生活生活 Dll 有名称不同的多个版本)中的有三个导出函数,但可能写有三个简单的线程作为观察,编译器将不要再让目标线程导入对应的 Dll,全都 把 memset 直接插入到目标线程的代码段。

  SSE2 全称是 Streaming SIMD Extention2, SIMD 全称是 Single-Instruction, Multiple-Data,是 Intel MMX 技术支持的一种生活生活单指令多数据运行模型,其目的为提高多媒体和通讯应用线程的性能。

  关于 SSE2,我将引用 Intel 的文档内容简要介绍如下:

  (3.1)可能 _Dst 那么对齐到 DWORD,则先把前面未对齐次要(1~3 bytes),以字节为单位循环设置。

  下面给出的是 memset 在 IDE 中的汇编代码,来自于 Micrsoft Visual Studio X\VC\crt\src\intel\memset.asm 的内容(下面的汇编代码在以字节为单位时使用的是 MOV [EDI], AL, 而在实际编译结果中是 rep stosb):

  以上是 memset 的最好的办法 的过程,底下当我门当我门将都看当 CPU 支持 SSE2 时的分支和上述步骤相同,全都 第二步中基本单位的粒度更大(128 bit / 16 bytes)。

  SSE2 在 Pentium 4 和 Intel Xeon 补救器中引入,提高了 3-D 图形,视频编码解码,语音识别,互联网,科学技术和工程应用线程的性能。提供 128-bit 的数据类型和相关指令,8 个 128-bit XMM 寄存器(XMM0~XMM7)。底下里能 都看,当 CPU 支持 SSE2 时,memset 将采用 SSE2 进行批量设置,每条指令可赋值 16 Bytes。

  可能要把所有元素赋值为任意有三个常数值,则 memset 那么达到要求,里能 用高级语言的循环进行赋值。

  通过 CPUID.01H (EAX=01H) 指令,可能 EDX.SSE2 [ bit 26 ] = 1,则支持 SSE2 扩展。

  (2)对数组用循环初始化时(这里假设数组元素类型为 int),编译器将其补救为 rep stosd 指令。

  (1)在数组被声明时提供初始化列表(且语言上仅能在声明时提供),其语法定义时对于缺省元素将使用 0 填充。在 MSVC 编译器的 release 输出中,将后续元素使用 memset 进行初始化。

  一种生活生活看法首先是毫无道理的,在代码风格,可读性,可维护性上根本不构成有三个命题,且 memset 在开发中的使用是非常常见的。一种生活生活错误观点来自于对代码风格和语言的僵硬理解,事先 当我门当我门将都看在编译器补救后两者的等效性。

  (3.2)主要循环次要 rep stosd 串存储指令,以 DWORD (4 bytes) 为基本单位循环设置。

  memset(a, 0, sizeof(a));

  可能把所有元素赋值为 -1 ( signed ) / 最大值 (unsigned) , 里能 用 memset (a, 0xFF, sizeof ( a ));

  int a[...] = { 0 };

  void* __cdecl memset (void* _Dst, int _Val, size_t _Size);

  (3.3)可能还有或多或少字节(1~3 bytes)未被设置,则以字节为单位循环设置。

  可能多媒体数据补救的行态是,常见在少许的小元素(BYTE,WORD,DWORD 等)组成的连续数据上进行相同的操作,全都 里能 在根小指令中提高数据吞吐能力来提高效率(即每次把多个数据打包成一组进行相同的并行操作),即 SIMD。(我的解释性评论,2014年5月3日补充 -- hoodlum1960 )

  (3)memset 的实现。

  第三个参数虽然为 int 类型,但会 函数针对的目标是字节,全都 它实际上提供的是有三个字节的值。首先给出该函数的常规实现过程(底下当我门当我门将分析在 CPU 支持 sse2 时的分支)的基本结论:

  memset 是 msvcrt 中的有三个函数,其作用和用途是显而易见的,通常是对一段内存进行填充,就其作用一种生活生活不具有任何歧义性。但都在人一定要纠结对数组的初始化一定要写成如下形式:

  本文讨论的前提条件是:操作系统平台为 windows 系统,编译器为 VS60 5 中的 VC,编译输出选项主要为 Release,反汇编工具为 VC 一种生活生活和 IDA。下面将给出或多或少经过实际观察和分析得到的基本结论,