当前位置: 首页 > news >正文

游戏引擎学习第五天

这节貌似没讲什么
视频参考:https://www.bilibili.com/video/BV1Gmm2Y5EwE/

uint8 *A = somewhere in memory;
uint8 *B = somewhere in memory;//BEFORE WE GOT TO HERE
int Y = *B; // == whatever was actually there before the 5
*A = 5;
int X = *B; // == 5
//Obviously! Y and X 
//DUH? The compiler should just load it once

在你的代码示例中:

以下是对每部分的解释:

  • uint8 *Auint8 *B:这两个是指向内存位置的指针,指向某个内存区域。具体的内存地址在代码中没有明确给出,因此我们不清楚它们指向的具体内存。

  • int Y = *B;:这行代码将指针 B 指向的内存位置的值解引用(即读取 *B)并将其赋值给 Y

  • *A = 5;:这行代码将指针 A 指向的内存位置的值设置为 5

  • int X = *B;:最后,代码再次解引用指针 B,将其值赋给 X

问题:为什么编译器不应该重新加载 *B,而是直接使用 Y 的值?

  • “编译器应该只加载一次”: 这段注释表示,从理论上讲,一旦 *B 的值被加载到 Y 中,之后不应该再次加载,因为在代码中并没有直接修改 B 指向的内存。因此,编译器本可以通过将 *B 的值存储到临时变量中,从而避免在 X 的赋值中再次解引用 B

为什么这种优化可能没有发生?

  1. 内存访问优化: 编译器在优化内存访问时,通常假设内存可能被程序的其他部分修改,尤其是如果这些内存可能是共享的。比如,AB 如果指向同一内存区域,或者内存的值可能被其他线程或硬件修改,编译器就不能假设 *B 在两次访问之间没有发生变化。

  2. 指针别名(Pointer Aliasing): 如果 AB 是指向同一块内存区域的指针,编译器不能假设 *B 的值在两次解引用之间不变,因为对 *A 的赋值可能会影响到 *B(例如,AB 指向同一内存)。因此,编译器不能简单地优化掉第二次对 *B 的解引用。

  3. 优化标志: 现代编译器有不同的优化等级,某些优化(如这类优化)只有在设置了较高的优化标志时才会执行(例如,GCC 中的 -O2-O3)。如果没有进行优化,或者优化级别较低(如 -O0),编译器可能不会执行这种优化。

  4. 内存的易变性(Volatility): 如果 AB 指向的内存被标记为 volatile,编译器就会强制每次都解引用它们,而不进行任何假设或优化。volatile 常用于与内存映射的 I/O、硬件寄存器或并发环境中的共享内存交互。

总结

简单来说,编译器 可以 通过将 *B 的值存储到一个临时变量中,避免第二次解引用 *B(即优化掉这次内存加载),前提是 编译器能够保证 *B 的值在两次解引用之间没有改变。然而,由于指针别名、并发操作或其他潜在的副作用,编译器可能不能进行这种优化。编译器是否进行优化取决于它对内存模型的理解以及它是否能保证两次解引用之间 *B 的值不变。

在这段代码中,MSG Message; 的声明位置取决于你对 MSG 变量的作用范围的需求。一般来说,建议将其声明放在 while 循环内部,而不是外部,原因如下:

  1. 局部性和性能:
    如果将 MSG 声明放在循环外部,MSG 变量将在每次循环时保持其值,可能导致不必要的残留数据。如果将其放在循环内部,每次循环都会创建一个新的 MSG 变量,避免了不必要的状态残留。

  2. 清晰的作用范围:
    MSG Message; 放在循环内部可以限制其作用范围,使得它只在当前的循环中有效。这使得代码更加清晰,并且减少了作用域问题。例如,如果你在多个地方使用 Message,会更容易理解它的生命周期和作用域。

  3. 避免潜在的逻辑错误:
    如果 MSG Message; 放在循环外部,它可能会在消息队列没有更新时继续保留上一个循环的消息,这可能会导致错误的行为。将其放在内部能确保每次迭代都能正确接收和处理新的消息。

因此,将 MSG Message; 放在 while 循环内部是更好的选择。你的代码可以这样优化:

if (Window) { // 检查窗口句柄是否有效,若有效则进入消息循环int xOffset = 0;int yOffset = 0;Running = true;while (Running) { // 启动一个无限循环,等待和处理消息MSG Message;    // 将 MSG 声明移至 while 循环内部while (PeekMessage(&Message,0, // hWnd 为 NULL,则检查当前线程中所有窗口的消息0, 0, // 用于设定消息类型的范围PM_REMOVE // 将消息从消息队列中移除,类似于 GetMessage 的行为)) {if (Message.message == WM_QUIT) {Running = false;}TranslateMessage(&Message); // 翻译消息,如果是键盘消息需要翻译DispatchMessage(&Message); // 分派消息,调用窗口过程处理消息}RenderWeirdGradient(xOffset, yOffset); // 渲染{HDC DeviceContext = GetDC(Window);RECT WindowRect;GetClientRect(Window, &WindowRect);int WindowWidth = WindowRect.right - WindowRect.left;int WindowHeight = WindowRect.bottom - WindowRect.top;Win32UpdateWindow(DeviceContext, &WindowRect, 0, 0, WindowWidth, WindowHeight);ReleaseDC(Window, DeviceContext);}++xOffset;}
}

这样可以确保每次循环都从消息队列中正确获取新的消息,并且 MSG 变量的作用范围是局部的。

根据您提供的栈中变量地址和内容,可以绘制出堆栈结构图,展示各个局部变量如何在栈帧中存储。以下是一个简化的堆栈结构图:

栈结构图

+----------------------------------------------------+  <- 栈顶
|                    返回地址                        |  
+----------------------------------------------------+  
|                参数 cmdshow (int *)                |  <- 参数 cmdshow 存储在此,指向栈上的一个 int 值
|                0x000000721a8ffbc8                   |  
+----------------------------------------------------+  
|                参数 cmdline (char **)              |  <- 参数 cmdline 存储在此,指向栈上的一个字符串
|                0x000000721a8ffbc0                   |  
+----------------------------------------------------+  
|           参数 hInstPrev (HINSTANCE__ **)          |  <- 参数 hInstPrev 存储在此,指向一个空指针
|                0x000000721a8ffbb8                   |  
+----------------------------------------------------+  
|           参数 hInst (HINSTANCE__ **)               |  <- 参数 hInst 存储在此,指向一个有效的 HINSTANCE
|                0x000000721a8ffbb0                   |  
+----------------------------------------------------+  
|              WindowClass (WNDCLASS)                |  <- WindowClass 存储在此
|                0x000000721a8ff2f0                   |  
|                style = 0                           |  
|                lpfnWndProc = 0x0000000000000000     |  
|                cbClsExtra = 0                      |  
|                ...                                 |  
+----------------------------------------------------+  
|           BigOldBlockOfMemory (1024KB)             |  <- 大的内存块,占用 1024KB
|                0x000000721a8042d0                   |  
|                [1024KB 内存空间]                   |  <- 1MB 数据
+----------------------------------------------------+  <- 栈底

在这里插入图片描述

解释:

  1. 栈顶(返回地址):函数 WinMain 返回时,程序会跳到此地址。
  2. 参数 cmdshow, cmdline, hInstPrev, hInst:这些参数的值存储在栈帧中,按顺序排列:
    • cmdshow 存储了一个 int * 类型的地址,指向栈上的值 10
    • cmdline 存储了一个 char ** 类型的地址,指向栈上的字符串(为空字符串)。
    • hInstPrev 存储了一个 HINSTANCE__ ** 类型的地址,指向 NULL
    • hInst 存储了一个 HINSTANCE__ ** 类型的地址,指向有效的程序映像基址 game.exe
  3. WindowClass:是一个 WNDCLASS 结构体,包含多种成员(如 style, lpfnWndProc 等)。每个成员被初始化为零或 nullptr
  4. BigOldBlockOfMemory:这是一个 1MB 大小的 uint8 数组,栈上分配。它存储在 BigOldBlockOfMemory 地址处,内部包含 1024KB 的数据。

注意:

  • 栈分配顺序:栈的分配是从高地址向低地址方向进行的,所以栈顶的变量(返回地址)先存储,然后是函数参数,最后是局部变量(如 WindowClassBigOldBlockOfMemory)。
  • 指针的存储:对于指针类型的变量(如 cmdshow, cmdline, hInstPrev, hInst),它们存储的是指向实际数据的地址。这些数据的内容在栈帧中的其他位置。
// game.cpp : Defines the entry point for the application.
//#include <cstdint>
#include <stdint.h>
#include <windows.h>#define internal static        // 用于定义内翻译单元内部函数
#define local_persist static   // 局部静态变量
#define global_variable static // 全局变量typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;struct win32_offscreen_buffer {BITMAPINFO Info;void *Memory;// 后备缓冲区的宽度和高度int Width;int Height;int Pitch;int BytesPerPixel;
};// TODO: 全局变量
global_variable bool Running;
global_variable win32_offscreen_buffer GlobalBackbuffer;// 添加这个去掉重复的冗余代码
struct win32_window_dimension {int Width;int Height;
};win32_window_dimension Win32GetWindowDimension(HWND Window) {win32_window_dimension Result;RECT ClientRect;GetClientRect(Window, &ClientRect);// 计算绘制区域的宽度和高度Result.Height = ClientRect.bottom - ClientRect.top;Result.Width = ClientRect.right - ClientRect.left;return Result;
}// 渲染一个奇异的渐变图案
internal void RenderWeirdGradient(win32_offscreen_buffer Buffer, int BlueOffset,int GreenOffset) {// TODO:让我们看看优化器是怎么做的uint8 *Row = (uint8 *)Buffer.Memory;      // 指向位图数据的起始位置for (int Y = 0; Y < Buffer.Height; ++Y) { // 遍历每一行uint32 *Pixel = (uint32 *)Row;          // 指向每一行的起始像素for (int X = 0; X < Buffer.Width; ++X) { // 遍历每一列uint8 Blue = (X + BlueOffset);         // 计算蓝色分量uint8 Green = (Y + GreenOffset);       // 计算绿色分量*Pixel++ = ((Green << 8) | Blue);      // 设置当前像素的颜色}Row += Buffer.Pitch; // 移动到下一行}
}// 这个函数用于重新调整 DIB(设备独立位图)大小
internal void Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int width,int height) {// device independent bitmap(设备独立位图)// TODO: 进一步优化代码的健壮性// 可能的改进:先不释放,先尝试其他方法,再如果失败再释放。if (Buffer->Memory) {VirtualFree(Buffer->Memory, // 指定要释放的内存块起始地址0, // 要释放的大小(字节),对部分释放有效,整体释放则设为 0MEM_RELEASE); // MEM_RELEASE:释放整个内存块,将内存和地址空间都归还给操作系统}// 赋值后备缓冲的宽度和高度Buffer->Width = width;Buffer->Height = height;Buffer->BytesPerPixel = 4;// 设置位图信息头(BITMAPINFOHEADER)Buffer->Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 位图头大小Buffer->Info.bmiHeader.biWidth = Buffer->Width; // 设置位图的宽度Buffer->Info.bmiHeader.biHeight =-Buffer->Height; // 设置位图的高度(负号表示自上而下的方向)Buffer->Info.bmiHeader.biPlanes = 1; // 设置颜色平面数,通常为 1Buffer->Info.bmiHeader.biBitCount =32; // 每像素的位数,这里为 32 位(即 RGBA)Buffer->Info.bmiHeader.biCompression =BI_RGB; // 无压缩,直接使用 RGB 颜色模式// 创建 DIBSection(设备独立位图)并返回句柄// TODO:我们可以自己分配?int BitmapMemorySize =(Buffer->Width * Buffer->Height) * Buffer->BytesPerPixel;Buffer->Memory = VirtualAlloc(0, // lpAddress:指定内存块的起始地址。// 通常设为 NULL,由系统自动选择一个合适的地址。BitmapMemorySize, // 要分配的内存大小,单位是字节。MEM_COMMIT, // 分配物理内存并映射到虚拟地址。已提交的内存可以被进程实际访问和操作。PAGE_READWRITE // 内存可读写);Buffer->Pitch = width * Buffer->BytesPerPixel; // 每一行的字节数// TODO:可能会把它清除成黑色
}// 这个函数用于将 DIBSection 绘制到窗口设备上下文
internal void Win32DisplayBufferInWindow(HDC DeviceContext, int WindowWidth,int WindowHeight,win32_offscreen_buffer Buffer, int X,int Y, int Width, int Height) {// 使用 StretchDIBits 将 DIBSection 绘制到设备上下文中StretchDIBits(DeviceContext, // 目标设备上下文(窗口或屏幕的设备上下文)/*X, Y, Width, Height, // 目标区域的 x, y 坐标及宽高X, Y, Width, Height,*/0, 0, WindowWidth, WindowHeight,   //0, 0, Buffer.Width, Buffer.Height, //// 源区域的 x, y 坐标及宽高(此处源区域与目标区域相同)Buffer.Memory,  // 位图内存指针,指向 DIBSection 数据&Buffer.Info,   // 位图信息,包含位图的大小、颜色等信息DIB_RGB_COLORS, // 颜色类型,使用 RGB 颜色SRCCOPY); // 使用 SRCCOPY 操作符进行拷贝(即源图像直接拷贝到目标区域)
}LRESULT CALLBACK
Win32MainWindowCallback(HWND hwnd, // 窗口句柄,表示消息来源的窗口UINT Message, // 消息标识符,表示当前接收到的消息类型WPARAM wParam, // 与消息相关的附加信息,取决于消息类型LPARAM LParam) { // 与消息相关的附加信息,取决于消息类型LRESULT Result = 0; // 定义一个变量来存储消息处理的结果switch (Message) { // 根据消息类型进行不同的处理case WM_CREATE: {OutputDebugStringA("WM_CREATE\n");};case WM_SIZE: { // 窗口大小发生变化时的消息} break;case WM_DESTROY: { // 窗口销毁时的消息// TODO: 处理错误,用重建窗口Running = false;} break;case WM_CLOSE: { // 窗口关闭时的消息// TODO: 像用户发送消息进行处理Running = false;} break;case WM_ACTIVATEAPP: { // 应用程序激活或失去焦点时的消息OutputDebugStringA("WM_ACTIVATEAPP\n"); // 输出调试信息,表示应用程序激活或失去焦点} break;case WM_PAINT: { // 处理 WM_PAINT 消息,通常在窗口需要重新绘制时触发PAINTSTRUCT Paint; // 定义一个 PAINTSTRUCT 结构体,保存绘制的信息// 调用 BeginPaint 开始绘制,并获取设备上下文 (HDC),同时填充 Paint 结构体HDC DeviceContext = BeginPaint(hwnd, &Paint);// 获取当前绘制区域的左上角坐标int X = Paint.rcPaint.left;int Y = Paint.rcPaint.top;// 计算绘制区域的宽度和高度int Height = Paint.rcPaint.bottom - Paint.rcPaint.top;int Width = Paint.rcPaint.right - Paint.rcPaint.left;win32_window_dimension Dimension = Win32GetWindowDimension(hwnd);Win32DisplayBufferInWindow(DeviceContext, Dimension.Width, Dimension.Height,GlobalBackbuffer, X, Y, Width, Height);#if 0local_persist DWORD Operation = WHITENESS;// 使用 WHITENESS 操作符填充矩形区域为白色PatBlt(DeviceContext, X, Y, Width, Height, Operation);// 设置窗体的颜色在刷新时白色和黑色之间来回变换if (Operation == WHITENESS) {Operation = BLACKNESS;} else {Operation = WHITENESS;}
#endif// 调用 EndPaint 结束绘制,并释放设备上下文EndPaint(hwnd, &Paint);} break;default: { // 对于不处理的消息,调用默认的窗口过程Result = DefWindowProc(hwnd, Message, wParam,LParam); // 调用默认窗口过程处理消息} break;}return Result; // 返回处理结果
}int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, //PSTR cmdline, int cmdshow) {uint8 BigOldBlockOfMemory[1004 * 1024];WNDCLASS WindowClass = {};// 使用大括号初始化,所有成员都被初始化为零(0)或 nullptrWin32ResizeDIBSection(&GlobalBackbuffer, 1280, 720);// WindowClass.style:表示窗口类的样式。通常设置为一些 Windows// 窗口样式标志(例如 CS_HREDRAW, CS_VREDRAW)。WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// CS_HREDRAW 当窗口的宽度发生变化时,窗口会被重绘。// CS_VREDRAW 当窗口的高度发生变化时,窗口会被重绘//  WindowClass.lpfnWndProc:指向窗口过程函数的指针,窗口过程用于处理与窗口相关的消息。WindowClass.lpfnWndProc = Win32MainWindowCallback;// WindowClass.hInstance:指定当前应用程序的实例句柄,Windows// 应用程序必须有一个实例句柄。WindowClass.hInstance = hInst;// WindowClass.lpszClassName:指定窗口类的名称,通常用于创建窗口时注册该类。WindowClass.lpszClassName = "gameWindowClass"; // 类名if (RegisterClass(&WindowClass)) {             // 如果窗口类注册成功HWND Window = CreateWindowEx(0,                         // 创建窗口,使用扩展窗口风格WindowClass.lpszClassName, // 窗口类的名称,指向已注册的窗口类"game",                    // 窗口标题(窗口的名称)WS_OVERLAPPEDWINDOW |WS_VISIBLE, // 窗口样式:重叠窗口(带有菜单、边框等)并且可见CW_USEDEFAULT, // 窗口的初始位置:使用默认位置(X坐标)CW_USEDEFAULT, // 窗口的初始位置:使用默认位置(Y坐标)CW_USEDEFAULT, // 窗口的初始宽度:使用默认宽度CW_USEDEFAULT, // 窗口的初始高度:使用默认高度0,             // 父窗口句柄(此处无父窗口,传0)0,             // 菜单句柄(此处没有菜单,传0)hInst,         // 当前应用程序的实例句柄0 // 额外的创建参数(此处没有传递额外参数));// 如果窗口创建成功,Window 将保存窗口的句柄if (Window) { // 检查窗口句柄是否有效,若有效则进入消息循环int xOffset = 0;int yOffset = 0;Running = true;while (Running) { // 启动一个无限循环,等待和处理消息MSG Message;    // 声明一个 MSG 结构体,用于接收消息while (PeekMessage(&Message,// 指向一个 `MSG` 结构的指针。`PeekMessage`// 将在 `lpMsg` 中填入符合条件的消息内容。0,// `hWnd` 为`NULL`,则检查当前线程中所有窗口的消息;// 如果设置为特定的窗口句柄,则只检查该窗口的消息。0, //0, // 用于设定消息类型的范围PM_REMOVE // 将消息从消息队列中移除,类似于 `GetMessage` 的行为。)) {if (Message.message == WM_QUIT) {Running = false;}TranslateMessage(&Message); // 翻译消息,如果是键盘消息需要翻译DispatchMessage(&Message); // 分派消息,调用窗口过程处理消息}RenderWeirdGradient(GlobalBackbuffer, xOffset, yOffset);// 这个地方需要渲染一下不然是黑屏{HDC DeviceContext = GetDC(Window);win32_window_dimension Dimension = Win32GetWindowDimension(Window);RECT WindowRect;GetClientRect(Window, &WindowRect);int WindowWidth = WindowRect.right - WindowRect.left;int WindowHeigh = WindowRect.bottom - WindowRect.top;Win32DisplayBufferInWindow(DeviceContext, Dimension.Width,Dimension.Height, GlobalBackbuffer, 0, 0,WindowWidth, WindowHeigh);ReleaseDC(Window, DeviceContext);}++xOffset;}} else { // 如果窗口创建失败// 这里可以处理窗口创建失败的逻辑// 比如输出错误信息,或退出程序等// TODO:}} else { // 如果窗口类注册失败// 这里可以处理注册失败的逻辑// 比如输出错误信息,或退出程序等// TODO:}return 0;
}

相关文章:

游戏引擎学习第五天

这节貌似没讲什么 视频参考:https://www.bilibili.com/video/BV1Gmm2Y5EwE/ uint8 *A somewhere in memory; uint8 *B somewhere in memory;//BEFORE WE GOT TO HERE int Y *B; // whatever was actually there before the 5 *A 5; int X *B; // 5 //Obviously! Y and …...

智能社区服务小程序+ssm

智能社区服务小程序 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了智能社区服务小程序的开发全过程。通过分析智能社区服务小程序管理的不足&#xff0c;创建了一个计算机管理智能社区服务小程序的方案。文…...

glide性能优化实战

glide性能优化实战 前言 项目使用glide加载图片之前也只是会基本api,这次项目有非常多的图片需要展示&#xff0c;而且设备是一个android12的版本&#xff0c;但是性能不太理想&#xff0c;分给APP的资源不太多&#xff0c;所以需要优化现有图片加载逻辑&#xff0c;读者可以…...

Python 环境搭建和安装(保姆级教程)

本章节我们将向大家介绍如何在本地搭建Python开发环境。 Python可应用于多平台包括 Linux 和 Mac OS X。 你可以通过终端窗口输入 "python" 命令来查看本地是否已经安装Python以及Python的安装版本。 Unix (Solaris, Linux, FreeBSD, AIX, HP/UX, SunOS, IRIX, 等…...

Java并发编程(二):同步机制与多线程是否矛盾

同步机制与多线程是否矛盾 0 纠正对异步和多选误解1 概述2 为什么要引入同步机制3 为什么多线程依然有意义3 总结 大家好&#xff0c;我是欧阳方超&#xff0c;可以关注我的公众号“欧阳方超”&#xff0c;后续内容将在公众号首发。 0 纠正对异步和多选误解 行文之前先纠正一下…...

golang分布式缓存项目 Day2 单机并发缓存

注&#xff1a;该项目原作者&#xff1a;https://geektutu.com/post/geecache-day1.html。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 支持并发读写 接下来我们使用 sync.Mutex 封装 LRU 的几个方法&#xff0c;使之支持并发的读写。在这之…...

一个百度、必应搜索引擎图片获取下载的工具包

前言&#xff1a;前段时间需要一大批图片&#xff0c;跑去百度搜图下载&#xff0c;发现特别麻烦&#xff0c;于是用了一天时间写了一个工具库&#xff0c;方便后续使用&#xff0c;这里分享给大家 imagecapture 是一个用 Go 语言编写的库&#xff0c;旨在从百度和必应等搜索引…...

安全见闻(网络安全篇)

笔记仅供学习&#xff0c;切勿触碰法律红线&#xff01; 以下笔记学习来自B站泷羽Sec&#xff1a;https://space.bilibili.com/350329294?spm_id_from333.337.search-card.all.click 如涉及侵权马上删除文章 1.编程语言 C语言&#xff1a;一种通用的、面向过程的编程语言&am…...

手写一些方法

模拟new方法 function Otaku(name,age) {this.name name;this.age age; this.habit Games}Otaku.prototype.strength 60;Otaku.prototype.sayName function () {console.log("I am " this.name);};function myNew(fn, ...args) {const obj Object.create(f…...

仅需三步!用AI工具免费打造10w+抖音爆款烟火秀视频教程

抖音上的烟火秀视频总能唤起人们对节日的温馨回忆&#xff0c;它们不仅视觉效果震撼&#xff0c;还自带流量属性。我自己在刷到这类视频时&#xff0c;也不禁回想起童年放烟花的快乐时光&#xff0c;那种浓厚的年味让人怀念。这些视频通常伴随着合适的音乐&#xff0c;能够迅速…...

基于redis实现API接口访问次数限制

一&#xff0c;概述 日常开发中会有一个常见的需求&#xff0c;需要限制接口在单位时间内的访问次数&#xff0c;比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢&#xff0c;通常大家都会想到用redis&#xff0c;确实通过redis可以实现这个功能&#xff0c…...

[ Linux 命令基础 3 ] Linux 命令详解-文件和目录管理命令

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

npm i 的时候报错: npm ERR! Error: EPERM: operation not permitted, rename

文章目录 噩梦解决办法总结 噩梦 最近改漏洞&#xff0c;这个项目删掉了 node_modules文件夹 重新安装依赖&#xff0c;结果安装一半的时候就一直报这个错。 然后查了很多方法&#xff0c;基本都是下面这些&#xff1a; 权限不够&#xff0c;以管理员运行cmd重新安装。清除 n…...

如何迁移剪映源文件

1、打开剪映&#xff0c;打开全局设置 2、查看草稿位置。把要迁移的文件拷贝到这个路径下面。 3、关闭文件&#xff0c;返回上一层界面&#xff0c;可以看到拷贝到目录下的文件。...

Go语言中的`io.Copy`函数:高效的数据复制解决方案

在Go语言中&#xff0c;io.Copy函数是一个强大而高效的工具&#xff0c;用于将数据从一个io.Reader复制到一个io.Writer。这篇文章将深入探讨io.Copy函数的工作原理、使用方法及其在实际应用中的优势。无论您是后端开发人员还是对Go语言感兴趣的程序员&#xff0c;这篇文章都将…...

datastage在升级版本到11.7之后,部分在11.3上正常执行的SP报错SQLSTATE = 22007: 本机错误代码 = -180

在升级版本到11.7之后&#xff0c;部分在11.3上正常执行的SP开始报错&#xff0c;报的SQL错误是时间参数问题&#xff0c;但是一样的SP可以直接call sp执行&#xff0c;也可以手动调用作业执行&#xff0c;只有设置定时调度时作业会报错&#xff0c; CALLXXX.XXX(1,CURRENT TIM…...

docker——项目部署

什么是Docker&#xff1f; Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可抑制的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器完全使用沙盒机制&#xff0c;相互之间不会存在任何接口。几…...

设计模式(Unity)——更新中

设计模式 文章目录 设计模式工厂模式创建方法&#xff08;Create Methods&#xff09;简单工厂&#xff08;Simple Factory&#xff09;工厂方法&#xff08;Method Factory&#xff09;抽象工厂&#xff08;Abstract Factroy&#xff09; 策略模式 工厂模式 创建方法&#xf…...

小程序中引入下载到本地的iconfont字体图标加载不出来问题解决

我这个是uniapp项目,字体图标都是一样的,在vue项目中web端、uniapp运行到h5都没问题,但是运行到小程序加载不出来,报错如下: 不让用本地路径,所以我们要转为base64编码,这里给大家提供一个工具,它可以把本地字体文件转为base64:transfonter 进入官网后,第一步: …...

百度富文本禁止编辑

<script type"text/javascript">$(function () {editorcontent new baidu.editor.ui.Editor();editorcontent.render(authentication);//禁用代码editorcontent.ready(function () {editorcontent.setDisabled();});try {editorcontent.sync();} catch (err) …...

C++开发基础之使用librabbitmq库实现RabbitMQ消息队列通信

1. 前言 RabbitMQ是一个流行的开源消息队列系统&#xff0c;支持多种消息协议&#xff0c;广泛用于构建分布式系统和微服务架构。可以在不同应用程序之间实现异步消息传递。在本文中&#xff0c;我们将熟悉如何使用C与RabbitMQ进行消息通信。 2. 准备工作 在 Windows 平台上…...

头歌网络安全(11.12)

头歌禁止复制解决 必须先下篡改猴&#xff01;&#xff01;&#xff01;&#xff01; 头歌复制助手 Educoder Copy Helperhttps://scriptcat.org/zh-CN/script-show-page/1860 Java生成验证码 第1关&#xff1a;使用Servlet生成验证码 任务描述 本关任务&#xff1a;使用se…...

洛谷 P1725 琪露诺(线段树优化dp)

题目链接 https://www.luogu.com.cn/problem/P1725 思路 我们令 d p [ i ] dp[i] dp[i]表示琪露诺移动到第 i i i个格子时能够获得的最大冰冻指数。 显然&#xff0c;状态转移方程为&#xff1a; d p [ i ] m a x ( d p [ i ] , d p [ k ] a [ i ] ) dp[i] max(dp[i],dp…...

【LeetCode】【算法】19. 删除链表的倒数第N个结点

LeetCode 19. 删除链表的倒数第N个结点 题目描述 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 思路 思路&#xff1a;快慢指针&#xff0c;快指针先移动n步&#xff0c;快慢指针再同时移动直到快指针到达链表末尾&#xff0c;此…...

Python爬虫 | 爬取豆瓣电影Top250的数据

简单记录一下&#xff0c;实现爬取豆瓣电影Top 250的数据。 这里我使用requests库来发送HTTP请求&#xff0c;以及BeautifulSoup库来解析HTML页面。 1.安装requests和BeautifulSoup库。 如果没有安装&#xff0c;可以通过以下命令安装&#xff1a; pip install requests bea…...

mac 中python 安装mysqlclient 出现 ld: library ‘ssl‘ not found错误

1. 出现报错 2. 获取openssl位置 brew info openssl 3. 配置环境变量&#xff08;我的是在~/.bash.profile&#xff09; export LDFLAGS"-L/opt/homebrew/Cellar/openssl3/3.4.0/lib" export CPPFLAGS"-I/opt/homebrew/Cellar/openssl3/…...

完全清除:苹果手机照片怎么彻底删除

在使用iPhone的过程中&#xff0c;由于拍摄积累的照片往往会占用大量存储空间。有时候&#xff0c;我们需要彻底删除这些照片以释放空间或保护隐私。苹果手机照片怎么彻底删除&#xff1f;在此&#xff0c;本文将与你分享一些实用的技巧。 彻底删除的重要性 彻底删除照片不仅涉…...

高德地图多个图片组成标点(自定义点标记内容)

图标的实现自定义点标记内容...

02-1_MVCC版本链清理

MVCC-版本链清理 文章目录 MVCC-版本链清理简介依赖机制Purge 操作的触发时机版本链清理的详细过程示例操作流程延迟清理配置和监控总结 简介 MySQL 中的 MVCC 机制通过版本链来管理数据的多版本存储&#xff0c;以支持高并发的读写操作。然而&#xff0c;随着事务的进行&…...

探索Python视频处理的瑞士军刀:ffmpeg-python库

文章目录 **探索Python视频处理的瑞士军刀&#xff1a;ffmpeg-python库**第一部分&#xff1a;背景介绍第二部分&#xff1a;ffmpeg-python库是什么&#xff1f;第三部分&#xff1a;如何安装ffmpeg-python库&#xff1f;第四部分&#xff1a;简单库函数使用方法1. 视频转码2. …...

做房产抵押网站需要什么/网络营销的基本内容有哪些

本文主要是把jdk8里面的lambda常用的例子摆一摆&#xff0c;忘记了看一看就知道怎么使用&#xff0c;方便回忆。 0&#xff0c;使用的循环体字段的代码&#xff0c;也就是操作对象&#xff0c;数据结构之类的&#xff0c;这里是简单的 list 数据。 private final List<BigD…...

亚马逊商标备案是否必须做网站/站长统计app下载

摘要&#xff1a;前言在日常的开发过程中,许多刚入行的开发者在apk打包命名、应用迭代版本的档案留存管理上都比较混乱——产生这些问题的原因无外乎以下两种:一是之前没有相关的操作经验、头尾不能兼顾;一是公司没有制定对应的规范、无有效参照范例。当然,所谓的规范在业内不会…...

seo长尾关键词排名/如何优化推广网站

前言工作中经常会用到&#xff0c;判断一个文件的文件类型&#xff0c;这里总结一把&#xff0c;一般判断文件类型的原理有2种方式&#xff1a;根据文件扩展名判断优点&#xff1a;速度快&#xff0c;代码简单缺点&#xff1a;无法判断出真实的文件类型&#xff0c;例如一些伪造…...

wordpress有点/手机打开国外网站app

知识点类静态数据成员 类静态成员函数一、类静态数据成员静态成员的提出是为了解决数据共享的问题。实现共享有许多方法&#xff0c;如&#xff1a;设置全局性的变量或对象是一种方法。但是&#xff0c;全局变量或对象是有局限性的。这一课里&#xff0c;我们主要讨论用类的静态…...

替换wordpress/seo咨询顾问

Gofakeit 是一款Go语言编写的随机数据生成工具&#xff0c;使用更易用的接口设计&#xff0c;可满足日常开发中绝大多数数据生成场景Gofakeit让您以更优雅的姿势生成测试数据。Gofakeit内置160函数&#xff0c;同时也很方便自定义。功能160内置函数!!!多个rand源全局rand支持st…...

wordpress制作ppt/汕头最好的seo外包

我姐不爽&#xff0c;就没来上自习……上了一早上的抽象代数和泛函。。。晕。寄予重望的资料还没出来&#xff0c;我的偏微啊中午给我们阿福他哥哥给整出门了&#xff0c;结果3点20才回到寝室来&#xff0c;见到客户不到10分钟&#xff0c;撅倒……下午在寝室混到吃饭&#xff…...