nasm - BasicWindow_64
文章目录
- nasm - BasicWindow_64
- 概述
- 笔记
- my_build.bat
- nasm_main.asm
- END
nasm - BasicWindow_64
概述
学习网上找到的demo.
x64和x86的汇编源码还差挺多的。
x64的汇编代码不好写,细节整不对,程序就不运行。
如果要查为啥不运行,也要看和正向生成的C工程的反汇编代码有哪些区别,才看的出来。
LEA, MOV很容易弄混。
MOV时,是否该加 地址数据类型的修饰(e.g. qword, dword), 这些也是细节。
感觉真是有需求用反汇编实现关键函数时,也是要以正向的代码生成的反汇编代码的基础上小步快跑的改,才不至于改了一坨后跑不起来。
笔记
my_build.bat
@echo off
clsrem ----------------------------------------
rem my_build.batrem env
rem NASM version 2.16.03 compiled on Apr 17 2024
rem GoLink.Exe Version 1.0.4.6 Copyright Jeremy Gordon 2002-2025set path=C:\Program Files\NASM;C:\soft\Golink;%path%rem . bat默认是不支持中文的 .
rem echo full path name - %~f0
rem echo full path - %~dp0
rem echo file name - %~nx0
rem echo work path - %cd%
rem all param - %*rem . rem注释的第1个字符和最后1个字符,不能是中文,否则有概率会当作命令来执行 .
rem . 调试.bat的方法 .
rem . 如果.bat写的不对,又不容易看出来,只能在每行后面加pause, 然后执行.bat, 然后按一下空格执行一行 .set prj_src_name_1=nasm_main.asm
set prj_obj_name_1=nasm_main.obj
set prj_exe_name=BasicWindow_64.exerem win32 or win64
set prj_build_type=win64rem /console or /SUBSYSTEM:WINDOWS
set prj_sub_sys=/SUBSYSTEM:WINDOWSecho [%~nx0 %*]if "%1" == "build" (call :fn_build
) else if "%1" == "clear" (call :fn_clear
) else (call :fn_usage
)goto endrem ----------------------------------------
rem function
rem ----------------------------------------:fn_usage
echo usage my_build.bat [option]
echo build - build asm to EXE
echo clear - clear trush on the project
exit /brem ----------------------------------------
:fn_build
echo build ...rem find file on work path
call :fn_del_file "%prj_obj_name_1%"nasm -f %prj_build_type% %prj_src_name_1% -o %prj_obj_name_1%
rem 用IDA打开.obj 已经可以看到实现逻辑了call :fn_del_file "%prj_exe_name%"rem 如果不指定要连接的dll, 会报错
golink /entry:fn_Start '%prj_sub_sys%' kernel32.dll user32.dll %prj_obj_name_1% /fo %prj_exe_name%call :fn_exec "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_clear
echo clear ...
call :fn_del_file "%prj_obj_name_1%"
call :fn_del_file "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_del_file
if exist "%~1" (echo del "%~1" del "%~1"
)
exit /b:fn_exec
if exist "%~1" (echo exec "%~1"%~1
)
exit /brem ----------------------------------------
:end
echo END
rem pause
call cmd
nasm_main.asm
; @file nasm_main.asm
; @brief 用NASM实现一个64bits的基本窗口
; nasm - BasicWindow_64
; ----------------------------------------
; 宏定义
; ----------------------------------------
; Basic Window, 64 bit. V1.01
COLOR_WINDOW EQU 5 ; Constants
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
CW_USEDEFAULT EQU 80000000h
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
NULL EQU 0
SW_SHOWNORMAL EQU 1
WM_DESTROY EQU 2
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000hWindowWidth EQU 640
WindowHeight EQU 480
; ----------------------------------------
; 导入函数声明
; ----------------------------------------
extern CreateWindowExA ; Import external symbols
extern DefWindowProcA ; Windows API functions, decorated
extern DispatchMessageA
extern ExitProcess
extern GetMessageA
extern GetModuleHandleA
extern IsDialogMessageA
extern LoadImageA
extern PostQuitMessage
extern RegisterClassExA
extern ShowWindow
extern TranslateMessage
extern UpdateWindow
; ----------------------------------------
; 区段定义
; ----------------------------------------
; 函数的入口名称是啥都可以, 只要link的时候指定主函数是啥
global fn_Start ; Export symbols. The entry pointsection .data ; Initialized data segmentWindowName db "Basic Window 64", 0ClassName db "Window", 0section .bss ; Uninitialized data segmenthInstance resq 1section .text ; Code segment
; ----------------------------------------
; 函数实现
; 如果对x64汇编不熟,可以先写一个x86版的NASM工程,正常用了,再改一个x64工程出来,比较简单,不用想事
; ----------------------------------------
fn_Start:sub RSP, 8 ; // 16对齐SUB RSP, 32XOR RCX, RCXcall GetModuleHandleAmov [hInstance], RAXADD RSP, 32call fn_WinMain; .LB_Exit:
XOR RCX, RCX
call ExitProcess
ret
; ----------------------------------------
fn_WinMain:
; 如果函数内有局部变量,需要自己开栈空间
; EBP - X 是局部变量
; EBP + X 是入参push RBP ; Set up a stack framemov RBP, RSPsub RSP, 136 + 8 ; 136 bytes for local variables. 136 is not; a multiple of 16 (for Windows API functions),; the + 8 takes care of this.%define wc RBP - 136 ; WNDCLASSEX structure, 80 bytes
%define wc.cbSize RBP - 136 ; 4 bytes. Start on an 8 byte boundary
%define wc.style RBP - 132 ; 4 bytes
%define wc.lpfnWndProc RBP - 128 ; 8 bytes
%define wc.cbClsExtra RBP - 120 ; 4 bytes
%define wc.cbWndExtra RBP - 116 ; 4 bytes
%define wc.hInstance RBP - 112 ; 8 bytes
%define wc.hIcon RBP - 104 ; 8 bytes
%define wc.hCursor RBP - 96 ; 8 bytes
%define wc.hbrBackground RBP - 88 ; 8 bytes
%define wc.lpszMenuName RBP - 80 ; 8 bytes
%define wc.lpszClassName RBP - 72 ; 8 bytes
%define wc.hIconSm RBP - 64 ; 8 bytes. End on an 8 byte boundary%define msg RBP - 56 ; MSG structure, 48 bytes
%define msg.hwnd RBP - 56 ; 8 bytes. Start on an 8 byte boundary
%define msg.message RBP - 48 ; 4 bytes
%define msg.Padding1 RBP - 44 ; 4 bytes. Natural alignment padding
%define msg.wParam RBP - 40 ; 8 bytes
%define msg.lParam RBP - 32 ; 8 bytes
%define msg.time RBP - 24 ; 4 bytes
%define msg.py.x RBP - 20 ; 4 bytes
%define msg.pt.y RBP - 16 ; 4 bytes
%define msg.Padding2 RBP - 12 ; 4 bytes. Structure length padding%define hWnd RBP - 8 ; 8 bytes
; 在函数内 %define x, 当使用x时,只在函数内生效mov dword [wc.cbSize], 80mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOWLEA RAX, [REL fn_WndProc] mov qword [wc.lpfnWndProc], RAXmov qword [wc.cbClsExtra], NULLmov qword [wc.cbWndExtra], NULLmov RAX, qword [REL hInstance]mov qword [wc.hInstance], RAXsub RSP, 32 + 16 ; // x64调用函数时,必须留shadow space, 这是x64函数调用约定,阴影区size = 32 = 4 x 8 = (size RCX + RDX + R8 + R9)mov qword [RSP + 32 + 1 * 8], LR_SHARED ; // param6mov qword [RSP + 32 + 0 * 8], NULL ; // param5XOR R9, R9 ; // param4mov R8, IMAGE_ICON ; // param3mov RDX, IDI_APPLICATION ; // param2XOR RCX, RCX ; // param1call LoadImageAmov [wc.hIcon], RAXadd RSP, 32 + 16; 调用WinApi时,是被调用者平衡堆栈(阴影区 + 入参)sub RSP, 32 + 16mov qword [RSP + 32 + 1 * 8], LR_SHAREDmov qword [RSP + 32 + 0 * 8], NULLXOR R9, R9MOV R8, IMAGE_CURSORMOV RDX, IDC_ARROWXOR RCX, RCXcall LoadImageAmov qword [wc.hCursor], RAXadd RSP, 32 + 16mov qword [wc.hbrBackground], COLOR_WINDOW + 1mov qword [wc.lpszMenuName], NULLLEA RAX, [REL ClassName]mov qword [wc.lpszClassName], RAX; 小图标内装的也是大图标...sub RSP, 32 + 16mov qword [RSP + 5 * 8], LR_SHAREDmov qword [RSP + 4 * 8], NULLmov R9, NULLmov R8, IMAGE_ICONmov RDX, IDI_APPLICATIONXOR ECX, ECXcall LoadImageA ; Small program iconmov qword [wc.hIconSm], RAXadd RSP, 32 + 16sub RSP, 32lea RCX, [wc]call RegisterClassExAadd RSP, 32; 假设操作数为x; [x] 代表x的地址; x 代表x是一个立即数; [REL x] 是相对RIP的地址,支持重定位, [x]是绝对地址,不支持重定位; 所以要优先考虑使用 [REL x] 这样的用法; mov [hWnd], RAX 和 mov qword [hWnd] 的区别; mov [hWnd], RAX 依赖于编译器推断, 在复杂寻址或者代码优化后可能不靠谱; 既然已经是汇编了, 还是最好是显势指定地址类型, e.g. mov qword [hWnd]; push qword [hInstance] 强制将hInstance的地址作为qword类型,不安全, 如果hInstance的类型size < sizeof(qword), 风险就来了; push [hInstance] 会自动扩展, 安全,优先使用这种来压栈; 但是 NASM中,push一个地址中的内容时,必须指定数据类型的size; 所以,如果一个数据地址的类型不是qwrod, 必须先载入寄存器(进行数据扩展,高端字节扩展为0),再将寄存器入栈; 如果 hWnd 是定义在栈上变量的别名,MOV RCX, [REL hWnd] 就是错误的,因为REL 是相对于RIP的相对便宜。; 应该用 MOV RCX, [hWnd]; LEA 地址的操作, MOV是数据的操作; e.g. lea RCX, [msg] 等价语句为 mov RCX, msg; 不过最好操作地址还是用 lea, 因为可以用REL修饰改为产生相对地址。; x64程序,参数的压入,最好使用手工调整RSP, 避免栈中数据不对齐和其他风险.; 入参在影子区后面(影子区结尾 = RSP + 32); parma1 = RSP + 32 + 0 *8; parma2 = RSP + 32 + 1 *8; parma3 = RSP + 32 + 2 *8; 准备调用 CreateWindowExA,入参12个, 4个在寄存器(RCX,RDX,R8,R9),其余8个需要入栈sub RSP, 32 + (8 * 8)mov qword [RSP + 32 + (7 * 8)], NULLmov RAX, qword [REL hInstance]mov qword [RSP + 32 + (6 * 8)], RAXmov qword [RSP + 32 + (5 * 8)], NULLmov qword [RSP + 32 + (4 * 8)], NULLmov qword [RSP + 32 + (3 * 8)], WindowHeightmov qword [RSP + 32 + (2 * 8)], WindowWidthmov dword [RSP + 32 + (1 * 8)], CW_USEDEFAULTmov dword [RSP + 32 + (0 * 8)], CW_USEDEFAULTmov R9, WS_OVERLAPPEDWINDOWLEA R8, [REL WindowName]LEA RDX, [REL ClassName]mov RCX, WS_EX_COMPOSITEDcall CreateWindowExAmov [hWnd], RAXadd RSP, 32 + (8 * 8) ; // 平衡栈指针, 阴影区 + 入参的8个参数(不算RCX, RDX, R8, R9)SUB RSP, 32MOV RDX, SW_SHOWNORMALMOV RCX, [hWnd]call ShowWindowADD RSP, 32SUB RSP, 32mov RCX, [hWnd]call UpdateWindowADD RSP, 32.LB_MessageLoop:SUB RSP, 32XOR R9, R9XOR R8, R8XOR RDX, RDXLEA RCX, [msg]call GetMessageAADD RSP, 32cmp EAX, 0je .LB_Fn_EndSUB RSP, 32LEA RDX, [msg]MOV RCX, [hWnd]call IsDialogMessageAADD RSP, 32cmp EAX, 0jne .LB_MessageLoop ; Skip TranslateMessage and DispatchMessageSUB RSP, 32LEA RCX, [msg]call TranslateMessageADD RSP, 32SUB RSP, 32lea RCX, [msg]call DispatchMessageAADD RSP, 32jmp .LB_MessageLoop; .LB_X 这种在函数内的标签的,作用域只在函数内
; 多个函数内,可以有多个同名的标签
; 所以函数内的标签一定要以.开头
.LB_Fn_End:mov RSP, RBP ; Remove the stack framepop RBPxor RAX, RAXret
; ----------------------------------------
fn_WndProc:push RBP ; Set up a Stack framemov RBP, RSP; 用RBP来标记入参比较好
; 入参开始栈地址为(RBP + 16)的原因, 因为进了函数栈顶是返回地址(+8), 然后又保存了RBP(+8)
; 此时RBP + 16 才是入参开始地址
%define hWnd RBP + 16 + (0 * 8) ; Location of the 4 passed parameters from
%define uMsg RBP + 16 + (1 * 8) ; the calling function
%define wParam RBP + 16 + (2 * 8) ; We can now access these parameters by name
%define lParam RBP + 16 + (3 * 8); 将前4个参数从寄存器写入阴影区, 然后就可以自由使用4个寄存器了,也可以从阴影区读取前4个入参了
MOV qword [hWnd], RCX
MOV qword [uMsg], RDX
MOV qword [wParam], R8
MOV qword [lParam], R9cmp qword [uMsg], WM_DESTROY ; [EBP + 12]je .LB_WMDESTROY; .LB_DefaultMessage:SUB RSP, 32MOV R9, qword [lParam]MOV R8, qword [wParam]MOV RDX, qword [uMsg]MOV RCX, qword [hWnd]call DefWindowProcAADD RSP, 32jmp .LB_fn_end.LB_WMDESTROY:SUB RSP, 32XOR RCX, RCXcall PostQuitMessageADD RSP, 32xor EAX, EAX.LB_fn_end:mov RSP, RBPpop RBPret
; ----------------------------------------; 如果先写好一个x86版本的实现,再从x86版改出一个x64版,挺麻烦的,容易搞错(x86和x64的汇编代码,其实差的还是挺多的,改还不如重写)
; 还是用VS2019写一个工程,编译成release + x64(关掉SDL,不优化),然后用IDA看,将需要的部分摘出来整理比较方便。
; NASM的代码实现和VS2019反汇编的代码基本一致,搬过来改,要方便的多。
END
相关文章:
nasm - BasicWindow_64
文章目录 nasm - BasicWindow_64概述笔记my_build.batnasm_main.asmEND nasm - BasicWindow_64 概述 学习网上找到的demo. x64和x86的汇编源码还差挺多的。 x64的汇编代码不好写,细节整不对,程序就不运行。 如果要查为啥不运行,也要看和正向…...

SpringBoot:SSL证书部署+SpringBoot实现HTTPS安全访问
一、前言 SSL协议介于TCP/IP协议栈的第四层(传输层)和第七层(应用层)之间,为基于TCP的应用层协议(如HTTP)提供安全连接。它通过在客户端和服务器之间建立一个加密的通道,确保数据在传…...

selenium爬取苏宁易购平台某产品的评论
目录 selenium的介绍 1、 selenium是什么? 2、selenium的工作原理 3、如何使用selenium? webdriver浏览器驱动设置 关键步骤 代码 运行结果 注意事项 selenium的介绍 1、 selenium是什么? 用于Web应用程序测试的工具。可以驱动浏览…...
Spark提交任务
1、Spark提交任务到Yarn 1.1、DwKuduApp spark-submit --class com.io.etl.dwkudu.DwKuduApp \ --files /etl/etl-dwkudu/conf/doris.property,/etl/etl-dwkudu/conf/redis.property,/etl/etl-dwkudu/conf/log4j.property \ --master yarn --deploy-mode cluster \ --driver-…...

游戏引擎学习第113天
仓库:https://gitee.com/mrxiao_com/2d_game_2 黑板:优化的基本过程 在游戏编程中,优化是一个非常重要的学习内容,尤其是想要成为专业开发者时。优化的核心是理解代码的执行速度,以及如何提升其性能。在这个阶段,已经…...
token是什么
在自然语言处理(NLP)和机器学习的背景下,token 是指模型在处理文本时的最小单位。通常,这个单位可以是单词、字符,或者词的一部分。具体来说,token 的定义取决于你使用的模型和它的分词方式。 举个例子&am…...

23. AI-大语言模型-DeepSeek赋能开发-Spring AI集成
文章目录 前言一、Spring AI 集成 DeepSeek1. 开发AI程序2. DeepSeek 大模型3. 集成 DeepSeek 大模型1. 接入前准备2. 引入依赖3. 工程配置4. 调用示例5. 小结 4. 集成第三方平台(已集成 DeepSeek 大模型)1. 接入前准备2. POM依赖3. 工程配置4. 调用示例…...
IPv6报头40字节具体怎么分配的?
目录 IPv6报头结构 字段详解 示例代码:IPv6报头的Python实现 输出示例 IPv6协议是为了解决IPv4地址耗尽问题而设计的下一代互联网协议。与IPv4相比,IPv6不仅提供了更大的地址空间,还简化了报头结构,提高了网络设备的处理效率。…...

驱动开发、移植
一、任务明确:把创龙MX8的驱动 按照我们的要求 然后移植到 我们的板子 1.Linux系统启动卡制作, sd卡 先按照 《用户手册—3-2-Linux系统启动卡制作及系统固化》 把创龙的Linux系统刷进去。 2. 把TLIMX8-EVM的板子过一遍 把刚刚烧好系统的sd卡插入 创…...

BFS与Flood Fill:算法原理、实现细节与复杂度分析
目录 1. 概述 2. BFS 的基本原理 3. Flood Fill 算法 4. BFS 实现 Flood Fill 的步骤 5. C 实现 6. 代码解析 7. 复杂度分析 8. 应用场景 总结 1. 概述 Flood Fill 算法是一种用于填充封闭区域的算法,常用于图像处理、绘图工具和游戏开发中。BFS(…...

计算机网络基础杂谈(局域网、ip、子网掩码、网关、DNS)
目录 1. 简单局域网的构成 2. IP 地址 3. 子网掩码 4. IP地址详解自定义IP 5. IP 地址详解 6. 网关 7. DNS 域名解析 8. ping 1. 简单局域网的构成 交换机是组建局域网最重要的设备,换句话说,没有交换机就没法搭建局域网 交换机不能让局域网连…...

雷龙CS SD NAND(贴片式TF卡)测评体验
一、产品概述 近期获赠雷龙科技(Longsto)推出的CS系列贴片式SD NAND存储解决方案,包含两片工业级贴片式NAND芯片(CSNP16GCR01-AOW)及全兼容转接板。该方案支持TF卡形态扩展,实现高可靠性嵌入式存储应用。 …...

【Alertmanager】alertmanager告警系统原理剖析与应用实战,应有尽有非常全面
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
Java——权限修饰符
一、权限修饰符的继承访问规则 以下按访问范围从宽到窄排序: 修饰符同包同类同包子类同包非子类跨包子类跨包非子类public✔️✔️✔️✔️✔️protected✔️✔️✔️✔️❌默认(包级)✔️✔️✔️❌❌private✔️❌❌❌❌ 关键点…...
一周学会Flask3 Python Web开发-redirect重定向
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们学过渲染到模板页面,这个其实是一种内部的转发,浏览器地址栏地址没有变化。如果我们想重定向…...
python面向对象:方法
1. 实例方法 实例方法用于操作实例变量,必须包含 self 参数。 class Person:def __init__(self, name):self.name namedef greet(self):print(f"Hello, my name is {self.name}")person1 Person("Alice") person1.greet() # 输出ÿ…...

物联网简介集合
物联网(IoT)指的是物理设备(如电器和车辆)之间的互联互通。这些设备嵌入了软件、传感器和连接功能,使其能够相互连接并交换数据。这项技术实现了从庞大的设备网络中收集和共享数据,为打造更高效、自动化的系…...
centos下使用pyenv管理python版本
在 CentOS 上安装 pyenv 和 pyenv-virtualenv,可以按照以下步骤进行操作: ps: centos7 最高适配到3.9.* 步骤 1:安装依赖 首先,确保你的系统中安装了必需的依赖项。你可以使用以下命令安装它们: [root ~]# yum gro…...

C++:类与对象,定义类和构造函数
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; //如何让定义一个类 // 封装 // 1、将数据和方法定义到一起。 // 2、把想给你看的数据给你看,不想给你看的封装起来。 通过访问限定符来实现 class Stack { public: //1.成…...

【Java消息队列】应对消息丢失、重复、顺序与积压的全面策略
应对消息丢失、重复、顺序与积压的全面策略 引言kafka消息丢失生产者消费者重复消费顺序消费消息积压生产者消费者其他RabbitMQ消息丢失生产者事务机制,保证生产者发送消息到 RabbitMQ Server发送方确认机制,保证消息能从交换机路由到指定队列保证消息在 RabbitMQ Server 中的…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...