这只猩猩很难控制 - Two star programming

2023-12-11 11:48

本文主要是介绍这只猩猩很难控制 - Two star programming,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Two star programming

2013-01-08 • C, Torvalds,Algorithms •46 Comments

A few weeks ago Linus Torvalds answered some questions on slashdot. All his responses make good reading but one in particular caught my eye. Asked to describe his favourite kernel hack, Torvalds grumbles he rarely looks at code these days — unless it’s to sort out someone else’s mess. He then pauses to admit he’s proud of the kernel’s fiendishly cunning filename lookup cache before continuing to moan about incompetence.

At the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc. For example, I’ve seen too many people who delete a singly-linked list entry by keeping track of the prev entry, and then to delete the entry, doing something like

if (prev)prev->next = entry->next;
elselist_head = entry->next;

and whenever I see code like that, I just go “This person doesn’t understand pointers”. And it’s sadly quite common.

People who understand pointers just use a “pointer to the entry pointer”, and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a*pp = entry->next.

Well I thought I understood pointers but, sad to say, if asked to implement a list removal function I too would have kept track of the previous list node. Here’s a sketch of the code:

This person doesn’t understand pointers
typedef struct node
{struct node * next;....
} node;typedef bool (* remove_fn)(node const * v);// Remove all nodes from the supplied list for which the 
// supplied remove function returns true.
// Returns the new head of the list.
node * remove_if(node * head, remove_fn rm)
{for (node * prev = NULL, * curr = head; curr != NULL; ){node * const next = curr->next;if (rm(curr)){if (prev)prev->next = next;elsehead = next;free(curr);}elseprev = curr;curr = next;}return head;
}

The linked list is a simple but perfectly-formed structure built from nothing more than a pointer-per-node and a sentinel value, but the code to modify such lists can be subtle. No wonder linked lists feature in so manyinterview questions!

The subtlety in the implementation shown above is the conditional required to handle any nodes removed from the head of the list.

Now let’s look at the implementation Linus Torvalds had in mind. In this case we pass in a pointer to the list head, and the list traversal and modification is done using a pointer to the next pointers.

Two star programming
void remove_if(node ** head, remove_fn rm)
{for (node** curr = head; *curr; ){node * entry = *curr;if (rm(entry)){*curr = entry->next;free(entry);}elsecurr = &entry->next;}
}

Much better! The key insight is that the links in a linked list are pointers and sopointers to pointers are the prime candidates for modifying such a list.

§

The improved version of remove_if() is an example of two star programming: the doubled-up asterisks indicate two levels of indirection. Athird star would be one too many.


体会: linus信手拈来的代码, 我却要花费半天时间去理解为什么它能工作

          我觉得有两点原因。 一: linus对指针理解的更深刻,(我尝试用汇编去理解**, 结果是它并不难理解)

                                        二: linus审阅的代码,或是写的代码比我多得多, (我远比不上linus聪明, 却比linus懒惰)


* 与 ** 与 变量名

node tmp;

node *p = &tmp;

node **pp = &p;

无论是*还是**,在32位系统上都是用栈空间里的4个字节表示

经编译后,在执行时 tmp变成栈里的一段空间,  (假设起始地址为 0xffffa0b0) (esp + 0x18)

p在栈里是4字节空间, 这4个字节的内容是tmp的地址 (则p的起始地址为 &p == 0xffffa0ac, 内容为: 0xb0 0xa0 0xff 0xff)  (esp + 0x14)

pp在栈里是4字节空间,这4个字节的内容是p的地址   (则pp的起始地址为 &pp == 0xffffa0a8, 内容为: 0xac 0xa0 0xff 0xff) (esp + 0x10)

mov 0x10(%esp) %eax    ; eax = 0xffffa0ac

mov (%eax) %eax             ; eax = 0xffffa0b0


对pp的赋值 是修改地址为0xffffa0a8的内容

对*pp的赋值 是修改地址为0xffffa0ac的内容


#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>typedef struct node {  int i;struct node *next;
} node;  typedef bool (*remove_fn)(node const *v);static int glo_cnt = 0;
bool cbfun(node const *v)
{glo_cnt++;if (glo_cnt % 2)return 0;return 1;
}void remove_if(node **head, remove_fn rm)
{node **curr;for (curr = head; *curr; ) {node * entry = *curr;if (rm(entry)) {*curr = entry->next;} else {curr = &entry->next;}}
}int main(int argc, char *argv[])
{struct node tmp[3] = {{1, &tmp[1]}, {2, &tmp[2]}, {3, NULL}};struct node *pnode = tmp;remove_if(&pnode, cbfun);for (pnode = tmp; pnode; pnode = pnode->next) {printf("%d ", pnode->i);}return 0;
}


原文链接: http://wordaligned.org/articles/two-star-programming

这篇关于这只猩猩很难控制 - Two star programming的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

Python远程控制MySQL的完整指南

《Python远程控制MySQL的完整指南》MySQL是最流行的关系型数据库之一,Python通过多种方式可以与MySQL进行交互,下面小编就为大家详细介绍一下Python操作MySQL的常用方法和最... 目录1. 准备工作2. 连接mysql数据库使用mysql-connector使用PyMySQL3.

如何搭建并配置HTTPD文件服务及访问权限控制

《如何搭建并配置HTTPD文件服务及访问权限控制》:本文主要介绍如何搭建并配置HTTPD文件服务及访问权限控制的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、安装HTTPD服务二、HTTPD服务目录结构三、配置修改四、服务启动五、基于用户访问权限控制六、

MySQL精准控制Binlog日志数量的三种方案

《MySQL精准控制Binlog日志数量的三种方案》作为数据库管理员,你是否经常为服务器磁盘爆满而抓狂?Binlog就像数据库的“黑匣子”,默默记录着每一次数据变动,但若放任不管,几天内这些日志文件就... 目录 一招修改配置文件:永久生效的控制术1.定位my.cnf文件2.添加核心参数不重启热更新:高手应

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络