达夫设备(Duff‘s Device)浅析

2024-01-23 20:20
文章标签 浅析 设备 device duff 达夫

本文主要是介绍达夫设备(Duff‘s Device)浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天偶尔看到 Duff’s Device C语言代码 , 凭兴趣研究了一下;
这段代码的来历是这样的:
达夫设备(Duff’s Device)是一段著名的C语言代码,由Tom Duff在1983年编写,用于手动展开循环以优化数据的复制操作。它是一种与众不同的编程技巧,结合了C语言中的switch语句和do…while循环结构,达到循环展开(unrolling)的效果,从而提高程序的运行效率。

下面是一个标准的达夫设备的示例代码:

void duff_device(char *to, char *from, int count)
{int n = (count + 7) / 8;switch (count % 8) {case 0: do { *to++ = *from++;case 7:      *to++ = *from++;case 6:      *to++ = *from++;case 5:      *to++ = *from++;case 4:      *to++ = *from++;case 3:      *to++ = *from++;case 2:      *to++ = *from++;case 1:      *to++ = *from++;} while (--n > 0);}
}

这段代码做的事情是将from指向的内存区域中的数据拷贝到to指向的内存区域中,拷贝的长度为count个字节。

解释一下代码的执行逻辑:

首先计算count除以8后向上取整的值给n,这将决定完整展开循环的次数。
然后通过count % 8获取剩余未处理的元素数量,作为switch语句的条件。
switch语句跳转到对应的case标签。这里的case标签作用是标记接下来需要执行的数据复制操作的起始点。
do…while循环开始执行,每次进入循环都执行8次数据复制操作,直到n减到0为止。当count不是8的倍数时,switch确保了从正确的地方开始复制。
达夫设备的核心优化思想是循环展开,通过减少循环迭代的次数来减少循环控制的开销,从而提高代码的执行效率。然而,这种技巧牺牲了代码的可读性,很容易导致代码维护上的困难,并且现代编译器的优化通常能够自动进行循环展开,所以它现在更多的是一个编程领域的趣闻,而不是推荐使用的代码实践。

读到这里 就自己动手实验了一下;
下面是我的实验代码


#include "test.h"void duff_device(char* to, char* from, int count)
{cout_time();int n = (count + 7) / 8;switch (count % 8) {case 0: do {*to++ = *from++;case 7:      *to++ = *from++;case 6:      *to++ = *from++;case 5:      *to++ = *from++;case 4:      *to++ = *from++;case 3:      *to++ = *from++;case 2:      *to++ = *from++;case 1:      *to++ = *from++;} while (--n > 0);}cout_time();
}int main()
{char s[100]="";char s1[100] = "hello world china";duff_device(s, s1, 17);std::cout << s <<std::endl;copy(s, s1, 17);std::cout << s << std::endl;
}void copy(char *to , char *from , int count)
{cout_time();for (int i = 0; i < count; i++) {*to++ = *from++;}cout_time();
}void cout_time()
{auto now = std::chrono::system_clock::now();//通过不同精度获取相差的毫秒数uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count()- std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000;time_t tt = std::chrono::system_clock::to_time_t(now);tm * time_tm = new tm();localtime_s(time_tm ,&tt);char strTime[25] = { 0 };sprintf_s(strTime, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900,time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour,time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds);std::cout << strTime << std::endl;delete time_tm;
}

达夫代码运行了3毫秒,普通循环运行了不到1毫秒
达夫代码运行了3毫秒,普通循环运行了不到1毫秒 , 使用的ide是 windows visual studio
猜测现在的编译器早就优化了;

这篇关于达夫设备(Duff‘s Device)浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/637409

相关文章

浅析Java如何保护敏感数据

《浅析Java如何保护敏感数据》在当今数字化时代,数据安全成为了软件开发中至关重要的课题,本文将深入探讨Java安全领域,聚焦于敏感数据保护的策略与实践,感兴趣的小伙伴可以了解下... 目录一、Java 安全的重要性二、敏感数据加密技术(一)对称加密(二)非对称加密三、敏感数据的访问控制(一)基于角色的访问

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

浅析如何使用xstream实现javaBean与xml互转

《浅析如何使用xstream实现javaBean与xml互转》XStream是一个用于将Java对象与XML之间进行转换的库,它非常简单易用,下面将详细介绍如何使用XStream实现JavaBean与... 目录1. 引入依赖2. 定义 JavaBean3. JavaBean 转 XML4. XML 转 J

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

浅析Python中的绝对导入与相对导入

《浅析Python中的绝对导入与相对导入》这篇文章主要为大家详细介绍了Python中的绝对导入与相对导入的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1 Imports快速介绍2 import语句的语法2.1 基本使用2.2 导入声明的样式3 绝对import和相对i

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可