C# 与 Windows API 交互的“秘密武器”:结构体和联合体
一、引言
在 C# 的编程世界里,当我们想要深入挖掘 Windows 系统的底层功能,与 Windows API 打交道时,结构体和联合体就像是两把神奇的钥匙🔑 它们能够帮助我们精准地操控数据,实现一些高级且强大的功能。就好比搭建一座精密的机器,每个零件都必须严丝合缝,结构体和联合体就是这些关键零件,确保我们与 Windows API 的交互顺畅无阻。今天,咱们就一起揭开它们神秘的面纱,看看在 C# 调用 Windows API 的过程中,它们究竟有着怎样的魔力。
二、结构体和联合体是什么?
(一)结构体的定义与特性
在 C# 中,结构体(Struct)是一种值类型,这意味着它在内存中有着独特的存储方式,与引用类型不同,值类型变量直接存储其数据,而不是存储对数据的引用。结构体就像是一个精致的收纳盒,能够将多个不同类型或者相同类型的数据成员有序地封装在一起。比如说,当我们在处理图形相关的编程任务时,常常需要表示一个点的坐标,这时就可以定义一个结构体:
// 定义一个结构体,用于存储点的坐标
public struct Point
{public int X;public int Y;public Point(int x, int y){X = x;Y = y;}
}
在上述代码中,我们清晰地定义了 Point 结构体,它包含了两个整型数据成员 X 和 Y,分别用于表示点在二维平面中的横坐标与纵坐标。结构体中的构造函数则为我们提供了便捷的初始化方式,就像给收纳盒里的物品设定初始摆放位置一样。在 Main 方法中,我们可以轻松地创建一个 Point 结构体的实例:
class Program
{static void Main(){// 创建一个点结构体实例Point p = new Point(10, 20);Console.WriteLine($"点P的坐标是: ({p.X}, {p.Y})");}
}
通过这段代码,我们将坐标点 (10, 20) 封装在 p 实例中,并且能够准确无误地将其坐标信息打印输出,是不是非常直观且方便呢?结构体这种能够将相关数据紧密捆绑在一起的特性,使得我们在处理复杂数据组合时,代码逻辑更加清晰,数据管理更加高效。
(二)联合体的独特之处
联合体(Union),从名字上看就感觉它有着特殊的魔力,它其实是一种特殊的结构体。想象一下,在同一个小小的内存空间里,它可以像一位神奇的换装大师,随时变换存储的数据类型。在 C 或 C++ 中,联合体有直接的语法支持,而在 C# 中,虽然没有原生的联合体关键字,但我们可以巧妙地借助结构体和显式布局来模拟出它的行为。比如说:
using System;
using System.Runtime.InteropServices;
// 定义一个模拟联合体的结构体
[StructLayout(LayoutKind.Explicit)]
public struct UnionExample
{[FieldOffset(0)]public int IntegerValue;[FieldOffset(0)]public double DoubleValue;
}
在这段代码中,我们通过 StructLayout(LayoutKind.Explicit) 属性精心规划了结构体的内存布局,让它按照我们期望的方式排列。再利用 FieldOffset(0) 属性,指明 IntegerValue 和 DoubleValue 这两个成员都从内存的起始位置(偏移量为 0)开始存储,这就意味着它们共享同一块内存区域。
接着,在 Main 方法中,我们来看看它的神奇表现:
class Program
{static void Main(){// 创建一个联合体实例,并设置整数值UnionExample u = new UnionExample();u.IntegerValue = 123;// 打印整数值Console.WriteLine($"整数值: {u.IntegerValue}");// 设置双精度浮点数值u.DoubleValue = 123.456;// 打印双精度浮点数值Console.WriteLine($"双精度浮点数值: {u.DoubleValue}");}
}
当我们先给 IntegerValue 赋值为 123 并打印时,一切都很正常。但当我们紧接着给 DoubleValue 赋值为 123.456 后,再去打印 IntegerValue,就会发现它的值已经发生了变化,不再是原来的 123。这是因为它们共享同一块内存,新的数据覆盖了旧的数据,就如同换装大师穿上了新衣服,旧衣服自然就看不到了。这种特性使得联合体在某些特定场景下,能够极大地节省内存空间,当我们明确知道在不同时刻只需要使用其中一种数据类型时,联合体就能发挥它的超能力。与结构体相比,结构体的每个成员都有自己独立的内存空间,数据相互独立,互不干扰;而联合体则是以牺牲数据的同时存在性为代价,换来内存利用的高效性,在不同的编程需求下,它们各自有着不可替代的优势。
三、结构体的魔法
(一)在 C# 中的定义和使用方式
在 C# 中定义结构体,就如同打造一个专属的工具盒。我们使用 struct 关键字开启结构体的定义之旅,在大括号内精心排列各种数据成员,这些成员可以是基本数据类型,如 int、double、string 等,也能是其他已定义的结构体类型,就像在收纳盒里放置不同种类的小物件。例如:
// 定义一个表示书籍信息的结构体
public struct Book
{public string Title;public string Author;public int PageCount;public Book(string title, string author, int pageCount){Title = title;Author = author;PageCount = pageCount;}
}
在这段代码里,Book 结构体如同一个精致的书籍档案夹,它收纳了书籍的标题 Title、作者 Author 以及页数 PageCount 这些关键信息,构造函数则为快速整理书籍档案提供了便捷方式。当我们在 Main 方法中使用它时:
class Program
{static void Main(){// 创建一个Book结构体实例Book myBook = new Book("《C#编程探秘》", "神秘博主", 300);Console.WriteLine($"书名:{myBook.Title},作者:{myBook.Author},页数:{myBook.PageCount}");}
}
通过实例化 Book 结构体,我们轻松地将一本虚拟书籍的信息封装其中,并准确地将这些信息展示出来,是不是感觉结构体就像是我们手中灵活的数据整理小助手呢?而且,结构体作为值类型,在赋值操作时会进行数据的完整拷贝,这意味着改变一个结构体实例的成员值,不会影响到其他副本,就像复制了多个一模一样的收纳盒,修改其中一个盒子里的物品,不会影响到其他盒子。
(二)实际应用场景举例
结构体在实际编程中的应用场景十分广泛,尤其是在与 Windows API 交互时,它常常扮演着数据传递使者的重要角色。在图形处理领域,当我们需要绘制图形、处理图像坐标或者判断图形之间的位置关系时,结构体就大显身手了。就拿前面提到的 Point 结构体来说,它可以精准地表示二维平面上的一个点的坐标,无论是绘制简单的线条、矩形,还是复杂的多边形,都离不开它对坐标点的准确描述。在绘制一个矩形时,我们可能会定义如下结构体:
[StructLayout(LayoutKind.Sequential)]
public struct Rectangle
{public Point TopLeft;public Point BottomRight;
}
这里的 Rectangle 结构体巧妙地利用了 Point 结构体,将矩形的左上角和右下角坐标封装起来,使得在图形绘制函数中传递矩形信息变得简洁明了。当调用绘制矩形的 Windows API 函数时,只需将 Rectangle 结构体实例作为参数传递,函数就能精准地获取矩形的位置和大小信息,在屏幕上绘制出我们期望的图形。
在系统信息获取方面,结构体同样不可或缺。比如,当我们想要获取系统的内存状态、CPU 信息或者窗口相关属性时,Windows API 提供了相应的函数,而这些函数往往要求以特定结构体作为参数来接收返回的数据。以获取系统内存状态为例,可能会有类似这样的结构体:
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_INFO
{public uint dwLength;public uint dwMemoryLoad;public uint dwTotalPhys;public uint dwAvailPhys;public uint dwTotalPageFile;public uint dwAvailPageFile;public uint dwTotalVirtual;public uint dwAvailVirtual;
}
通过调用相关的 Windows API 函数,并传入 MEMORY_INFO 结构体实例,函数就能将系统内存的各种详细信息填充到结构体的各个成员中,我们后续只需在 C# 代码中读取这些成员值,就能清晰地了解系统内存的使用情况,就像是拥有了一个系统内存的信息仪表盘,为优化系统性能提供精准的数据支持。
四、联合体的超能力
(一)C# 中模拟联合体的方法
在 C# 中,虽然没有像 C 或 C++ 那样直接使用 union 关键字来定义联合体,但我们拥有强大的.NET 框架特性,能够巧妙地模拟出联合体的神奇功能。关键就在于 StructLayout 和 FieldOffset 这两个属性。StructLayout 属性如同一位精密的建筑师,它精心规划结构体在内存中的布局方式。当我们将其设置为 LayoutKind.Explicit 时,就相当于告诉编译器:“嘿,我要按照自己的精确规划来安排结构体成员的内存位置。” 而 FieldOffset 属性则像是一个个精准的坐标标记,它指明了每个结构体成员在内存中的具体偏移量。
就拿之前提到的代码为例:
using System;
using System.Runtime.InteropServices;
// 定义一个模拟联合体的结构体
[StructLayout(LayoutKind.Explicit)]
public struct UnionExample
{[FieldOffset(0)]public int IntegerValue;[FieldOffset(0)]public double DoubleValue;
}
在这段代码里,[StructLayout(LayoutKind.Explicit)] 为 UnionExample 结构体设定了独特的内存布局规则,使其成员的存储打破常规。[FieldOffset(0)] 这个标记对于 IntegerValue 和 DoubleValue 来说,就如同将它们都精确地放置在内存的起始起跑线,意味着它们共享同一块初始内存区域。这就模拟出了联合体那种在同一内存位置存储不同数据类型的特性。当我们在 Main 方法中操作这个模拟联合体时:
class Program
{static void Main(){// 创建一个联合体实例,并设置整数值UnionExample u = new UnionExample();u.IntegerValue = 123;// 打印整数值Console.WriteLine($"整数值: {u.IntegerValue}");// 设置双精度浮点数值u.DoubleValue = 123.456;// 打印双精度浮点数值Console.WriteLine($"双精度浮点数值: {u.DoubleValue}");}
}
可以清晰地看到,先给 IntegerValue 赋值为 123 并打印,一切顺利。但当紧接着给 DoubleValue 赋值为 123.456 后,再次打印 IntegerValue,它的值已经被新的数据无情覆盖,不再是最初的 123。这正是联合体内存共享特性的生动体现,在 C# 中通过这样巧妙的模拟,我们同样能够驾驭这种强大的数据存储方式。
(二)应用优势与注意事项
联合体在实际应用中有着诸多独特的优势。最显著的一点就是它能够极大地节省内存空间。想象一下,在某些特定的场景下,比如处理一些传感器数据,我们可能在不同时刻只需要用到整数类型或者浮点类型来表示数据,这时使用联合体,让它们共享同一块内存,就避免了像结构体那样为每个成员开辟独立内存空间,从而有效减少内存的占用。就如同在一个狭小的储物箱里,通过合理安排物品的存放方式,让不同的物品在不同时间共用同一个空间,达到空间利用的最大化。
在与一些底层硬件交互或者解析特定格式的二进制数据时,联合体也能发挥关键作用。例如,在网络编程中接收数据包,数据包的头部可能根据不同的协议版本,某个字段既可以是整数表示的简单标识,也可以是复杂结构体表示的详细信息。这时,联合体就能让我们轻松应对这种数据格式的变化,根据实际情况灵活地将同一块内存区域解读为不同的数据类型,高效地解析数据包,确保数据传输的准确与流畅。
不过,使用联合体也需要格外小心,如同在钢丝上行走,稍有不慎就可能引发问题。由于成员共享同一块内存,数据覆盖的风险时刻存在。就像前面的例子,给一个成员赋值后,再给另一个共享内存的成员赋值,之前的值就会被覆盖丢失。所以在代码编写过程中,必须时刻牢记当前联合体中存储的数据类型,精准地操作对应的成员,避免出现数据混乱的情况。而且,这种内存共享的特性也使得联合体的代码可读性相对较差,对于后续维护代码的开发者来说,可能需要花费更多的精力去理解其中的数据流向和逻辑关系。因此,在使用联合体时,权衡好内存优化与代码可维护性之间的平衡至关重要,确保它在正确的场景下发挥最大的效能,而不是成为引发程序错误的 “定时炸弹”。
五、结构体和联合体在 Windows API 中的应用
(一)重要性体现
在与 Windows API 交互的过程中,结构体和联合体的重要性怎么强调都不为过。Windows API 作为 Windows 系统的底层接口,函数繁多且功能各异,它们就像一个个精密的工具,等待着我们用合适的数据去驱动。而结构体和联合体,恰恰就是构建这些精准数据的基石。许多 Windows API 函数需要特定格式的数据才能正常工作,结构体和联合体能够完美地将数据按照要求进行封装,以正确的格式传递给 API 函数,确保程序与 Windows API 之间的通信顺畅无阻,就如同为不同形状的拼图找到了恰好匹配的空位,让整个画面得以完整呈现。
比如说,当我们想要获取系统中某个窗口的详细信息时,Windows API 提供了 GetWindowInfo 这样的函数,但它要求传入一个特定结构体来接收返回的数据。这个结构体必须精确地定义各个成员的类型和顺序,以匹配 API 底层的期望。如果没有结构体来整齐划一地整理这些数据,我们就像是将一堆杂乱无章的零件丢给一个精密仪器,仪器根本无法正常运转,程序自然也就无法获取到准确的窗口信息,更别提后续的处理与操作了。
(二)具体实例剖析
让我们深入剖析一个获取窗口信息的实例,看看结构体是如何在其中发挥关键作用的。首先,我们定义了如下结构体:
using System;
using System.Runtime.InteropServices;
// 定义一个结构体,用于存储窗口信息
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWINFO
{public uint cbSize;public RECT rcWindow;public RECT rcClient;public uint dwStyle;public uint dwExStyle;public uint dwWindowStatus;public uint cxWindowBorders;public uint cyWindowBorders;public ushort atomWindowType;public ushort wCreatorVersion;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{public int left;public int top;public int right;public int bottom;
}
在这段代码中,WINDOWINFO 结构体宛如一个精心设计的窗口信息收纳盒,它的每个成员都各司其职。cbSize 成员就像是一个标识,告诉 API 函数这个结构体的大小,确保数据传输的准确性;rcWindow 和 rcClient 成员则通过嵌套的 RECT 结构体,精确地描述了窗口的整体矩形区域以及客户区矩形区域,从窗口的边界位置到内部可用区域的范围都能精准定位;其他成员如 dwStyle、dwExStyle 等,分别对应着窗口的样式、扩展样式以及各种状态信息,涵盖了窗口外观、行为等多方面的特征。
当我们在 Main 方法中调用 GetWindowInfo 函数时:
class Program
{[DllImport("user32.dll")]public static extern bool GetWindowInfo(IntPtr hWnd, ref WINDOWINFO pwi);static void Main(){// 假设我们已经获取到了目标窗口的句柄,这里用hwnd表示IntPtr hwnd = /* 获取窗口句柄的代码 */; WINDOWINFO windowInfo = new WINDOWINFO();windowInfo.cbSize = (uint)Marshal.SizeOf(windowInfo);bool result = GetWindowInfo(hwnd, ref windowInfo);if (result){Console.WriteLine($"窗口位置:({windowInfo.rcWindow.left}, {windowInfo.rcWindow.top}) - ({windowInfo.rcWindow.right}, {windowInfo.rcWindow.bottom})");Console.WriteLine($"客户区位置:({windowInfo.rcClient.left}, {windowInfo.rcClient.top}) - ({windowInfo.rcClient.right}, {windowInfo.rcClient.bottom})");Console.WriteLine($"窗口样式:{windowInfo.dwStyle}");// 可以继续输出其他成员信息}}
}
在上述代码中,首先我们通过 DllImport 引入 GetWindowInfo 函数,确保能够在 C# 代码中调用这个 Windows API 函数。接着,在 Main 方法里,我们假设有了目标窗口的句柄(实际应用中需要通过其他方式获取,如 FindWindow 函数等),创建了 WINDOWINFO 结构体实例并初始化 cbSize 成员,这一步至关重要,它让 API 函数知道要接收的数据结构大小。当调用 GetWindowInfo 函数后,如果返回值为 true,表示成功获取到窗口信息,此时我们就能像打开装满宝藏的箱子一样,从结构体的各个成员中取出窗口的详细信息,无论是窗口在屏幕上的坐标位置、客户区的范围,还是窗口的样式特征,都能一目了然,为后续对窗口的进一步操作,如移动、缩放、修改样式等提供了坚实的数据基础,让我们的程序能够与 Windows 系统的窗口进行深度交互,实现更加丰富多样的功能。
六、常见问题与解决策略
(一)定义和使用中的错误类型
在使用结构体和联合体与 Windows API 交互的过程中,我们就像在布满礁石的航道上航行,一不小心就可能触礁。常见的错误类型还真不少,比如说结构体成员类型不匹配,就像拿着错误尺寸的拼图碎片,怎么也塞不进对应的空位。当我们定义的结构体成员类型与 Windows API 要求的不一致时,可能导致数据传输错误,进而引发程序崩溃或者得到错误的结果。比如在调用一个获取网络数据包信息的 Windows API 函数时,结构体中某个表示数据包长度的成员,在 C# 中错误地定义为 int 类型,而 API 要求的是 uint 类型,这就可能导致读取数据包长度时出现负值或者溢出的情况,使得后续对数据包的解析完全错乱。
联合体内存布局错误也是一个容易让人掉进的 “陷阱”。由于联合体成员共享同一块内存,如果在定义联合体时,没有正确设置 FieldOffset 等属性,或者不小心改变了成员的顺序、大小,就会像打乱了房间里家具的摆放,导致数据存储和读取混乱。例如,在一个模拟硬件设备状态的联合体中,一个成员用于表示设备的开关状态(bool 类型),另一个成员用于表示设备的温度值(float 类型),如果错误地设置了偏移量,可能会出现读取开关状态时得到的却是温度值的一部分二进制数据,将其错误解读为开关状态,这显然会引发严重的逻辑错误。
还有结构体或联合体在跨平台使用时的兼容性问题,就如同在不同规格的轨道上行驶的火车,容易脱轨。不同的操作系统或者硬件平台,对数据的存储方式、字节对齐等可能存在差异。在 32 位系统上正常运行的结构体代码,移植到 64 位系统时,可能因为指针类型的长度变化、结构体的填充字节数不同等原因,导致数据错位,程序出现莫名其妙的错误。这就要求我们在编写代码时,要有前瞻性,充分考虑到可能的平台差异,使用合适的属性(如 StructLayout 的不同布局选项)来确保结构体和联合体在不同平台上都能稳定运行。
(二)调试技巧与工具推荐
当遇到这些棘手的问题时,别慌,我们有一些调试的 “秘密武器”。首先,善用 Visual Studio 的调试功能,它就像是我们的程序侦探。在调试模式下,可以逐步执行代码,观察结构体和联合体变量在每一步的变化,查看内存中的数据存储情况。通过设置断点,在关键代码行暂停执行,仔细检查变量的值是否符合预期。比如在调用 Windows API 函数前后,分别查看作为参数传递的结构体成员值,看是否在函数调用过程中被正确赋值或者修改。还可以利用监视窗口,实时跟踪结构体和联合体中各个成员的数值变化,一旦发现异常,就能迅速定位到问题代码所在。
另外,有一个非常实用的工具 ——P/Invoke Interop Assistant,它像是一位贴心的导航员,能帮助我们在复杂的 P/Invoke 调用中找到正确的方向。当我们对结构体或函数的声明不确定时,只需将 Native 函数或者结构的声明拷贝到工具的相应文本框,点击生成,就能获取对应的.NET 声明,避免了手动声明时容易出现的错误。而且它还能查找 Win32 API 在.NET 中的声明,验证我们编写的.NET 函数或结构在 C 中的声明是否正确,为跨语言调用保驾护航,大大提高了我们编写代码的效率和准确性,让我们在与 Windows API 交互的编程之旅中更加顺畅。
七、总结
通过这一趟深入的探索之旅,我们清晰地认识到结构体和联合体在 C# 与 Windows API 交互中无可替代的关键作用。结构体宛如一位严谨的数据管家,有条不紊地将各类相关数据整理打包,以精准无误的格式递交给 Windows API,确保信息传递的准确性,让我们的程序能够顺利获取系统资源、操控窗口等诸多强大功能。联合体则像一位神奇的空间魔法师,在特定场景下,通过巧妙共享内存,为我们节省宝贵的内存资源,特别是在处理一些对内存占用敏感、数据类型需灵活切换的任务时,展现出独特的优势。
然而,这一路上我们也看到了不少隐藏在暗处的 “礁石”,从结构体成员类型的匹配失误,到联合体内存布局的错乱,再到跨平台时兼容性的挑战,稍有不慎就可能让程序 “触礁”。但别怕,我们手握 Visual Studio 调试利器以及 P/Invoke Interop Assistant 导航仪,只要善加利用,就能在遇到问题时迅速找准方向,化险为夷。
希望大家在今后的编程实践中,大胆地运用结构体和联合体这两把神奇钥匙,开启 Windows API 的强大宝库,去探索更多未知的编程天地,让你的程序绽放出别样的光彩,轻松应对各种复杂的开发需求,向着编程高手之路大步迈进!
相关文章:
C# 与 Windows API 交互的“秘密武器”:结构体和联合体
一、引言 在 C# 的编程世界里,当我们想要深入挖掘 Windows 系统的底层功能,与 Windows API 打交道时,结构体和联合体就像是两把神奇的钥匙🔑 它们能够帮助我们精准地操控数据,实现一些高级且强大的功能。就好比搭建一…...
PHP 使用 Redis
PHP 使用 Redis PHP 是一种广泛使用的服务器端编程语言,而 Redis 是一个高性能的键值对存储系统。将 PHP 与 Redis 结合使用,可以为 Web 应用程序提供快速的读写性能和丰富的数据结构。本文将详细介绍如何在 PHP 中使用 Redis,包括安装、连接、基本操作以及一些高级应用。 …...
嵌入式系统Linux实时化(四)Xenomai应用开发测试
1、Xenomai 原生API 任务管理 Xenomai 本身提供的一系列多任务调度机制,主要有以下一些函数: int rt_task_create (RT_TASK task, const char name, int stksize, int prio, intmode) ; 任务的创建;int rt_task_start(RT_TASK task, void(entry)(void cookie), void cookie…...

26个开源Agent开发框架调研总结(2)
根据Markets & Markets的预测,到2030年,AI Agent的市场规模将从2024年的50亿美元激增至470亿美元,年均复合增长率为44.8%。 Gartner预计到2028年,至少15%的日常工作决策将由AI Agent自主完成,AI Agent在企业应用中…...
Element UI与Element Plus:深度剖析
文章目录 前言一、概述二、技术特性三、设计理念四、使用体验五、迁移指南结语 前言 随着前端开发技术的快速发展,Vue.js 生态系统中的组件库也在不断进化。Element UI 和 Element Plus 是两个深受开发者喜爱的 Vue 组件库,它们分别构建于 Vue 2.x 和 V…...

二、BIO、NIO编程与直接内存、零拷贝
一、网络通信 1、什么是socket? Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口,一般由操作 系统提供。客户端连接上一个服务端,就会在客户端中产生一个 socket 接口实例,服务端每接受 一个客户端…...
VSCode 更好用的设置
配置 {"terminal.integrated.fontSize": 15,"security.workspace.trust.untrustedFiles": "open","editor.minimap.enabled": false,"workbench.colorTheme": "Visual Studio 2017 Light - C","gnuGlobal.c…...

【git】-3 github创建远程仓库,上传自己的项目,下载别人的项目
一、如何使用Github 1、创建远程仓库 2、使用github拉取/推送代码 克隆仓库 向远程仓库推送代码-git push 二、上传我们自己的项目到github 方法一:直接上传 方法二:使用git命令 方法三: 将仓库拉取到本地上传 三、下载别人的项目 …...

计算机组成原理(1)
系统概述 计算机硬件基本组成早期冯诺依曼机现代计算机 计算机各部分工作原理主存储器运算器控制器计算机工作过程 此文章的图片资源获取来自于王道考研 计算机硬件基本组成 早期冯诺依曼机 存储程序是指将指令以二进制的形式事先输入到计算机的主存储器,然后按照…...

Openstack网络组件之Neutron
从Nova到Neutron:OpenStack网络架构的演变 在云计算和虚拟化技术迅猛发展的背景下,OpenStack 成为了构建私有云和公有云平台的首选解决方案之一。早期版本中,Nova 项目不仅负责计算资源的管理,还承担了提供基本网络连接的任务。然…...
神州数码交换机和路由器命令总结
神州数码交换机和路由器命令总结 一、神州数码交换机命令总结 1. 交换机恢复出厂设置及其基本配置. 1) //进入特权模式 2) del startup.cfg 2. Telnet方式管理交换机. 1) //进入全局配置模式 2) enable password 0 [密码] 3) Line 0 4 4) Password 0 [密码] 5) Login 3. 交换机…...

Spring MVC简单数据绑定
【图书介绍】《SpringSpring MVCMyBatis从零开始学(视频教学版)(第3版)》_springspringmvcmybatis从零开始 代码、课件、教学视频与相关软件包下载-CSDN博客 《SpringSpring MVCMyBatis从零开始学(视频教学版)(第3版&…...
《SQL ORDER BY》
《SQL ORDER BY》 介绍 SQL(Structured Query Language)是一种用于管理关系数据库管理系统的标准编程语言。ORDER BY语句是SQL中的一个重要部分,它用于对查询结果进行排序。在本篇文章中,我们将详细介绍SQL ORDER BY语句的用法、语法、示例以及一些高级应用。 语法 ORD…...

RabbitMQ基础(简单易懂)
RabbitMQ高级篇请看: RabbitMQ高级篇-CSDN博客 目录 什么是RabbitMQ? MQ 的核心概念 1. RabbitMQ 的核心组件 2. Exchange 的类型 3. 数据流向说明 如何安装RabbitQueue? WorkQueue(工作队列): Fa…...
DNS解析域名简记
域名通常是由: 权威域名.顶级域名.根域名组成的。 从左往右,级别依次升高,这和外国人从小范围到大范围的说话习惯相关。(我们自己是更习惯先说大范围再说小范围,如XX省XX市XX区XX路) DNS解析域名时,会先查…...

【2024年华为OD机试】(B卷,100分)- 求最小步数 (Java JS PythonC/C++)
一、问题描述 题目描述 求从坐标零点到坐标点 n 的最小步数,一次只能沿横坐标轴向左或向右移动 2 或 3。 注意:途径的坐标点可以为负数。 输入描述 坐标点 n 输出描述 输出从坐标零点移动到坐标点 n 的最小步数。 备注 1 < n < 10^9 用例…...
<C++> XlsxWriter写EXCEL
XlsxWriter XlsxWriter是一个用于创建和写入Excel 2007及以上版本(.xlsx文件格式)的C库。以下是对XlsxWriter的详细介绍: 主要功能 文本、数字和公式写入:可以向多个工作表中写入文本、数字和公式。格式设置:支持丰…...

接上一主题,实现QtByteArray任意进制字符串转为十进制数
函数: /// <summary>/// n进制字符串转为十进制数,snDefine的长度最小为二进制数。/// 例子:/// _pn(_Math::strNToInt(_t("1010"), _t("01")));/// _pn(_Math::strNToInt(_t("-1010"), _t("0123…...

CNN-GRU-MATT加入贝叶斯超参数优化,多输入单输出回归模型
CNN-GRU-MATT加入贝叶斯超参数优化,多输入单输出回归模型 目录 CNN-GRU-MATT加入贝叶斯超参数优化,多输入单输出回归模型预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现贝叶斯优化CNN-GRU融合多头注意力机制多变量回归预测ÿ…...

Java 如何传参xml调用接口获取数据
传参和返参的效果图如下: 传参: 返参: 代码实现: 1、最外层类 /*** 外层DATA类*/ XmlRootElement(name "DATA") public class PointsXmlData {private int rltFlag;private int failType;private String failMemo;p…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...