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…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...

表单设计器拖拽对象时添加属性
背景:因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...

免费批量Markdown转Word工具
免费批量Markdown转Word工具 一款简单易用的批量Markdown文档转换工具,支持将多个Markdown文件一键转换为Word文档。完全免费,无需安装,解压即用! 官方网站 访问官方展示页面了解更多信息:http://mutou888.com/pro…...

Modbus转Ethernet IP深度解析:磨粉设备效率跃升的底层技术密码
在建材矿粉磨系统中,开疆智能Modbus转Ethernet IP网关KJ-EIP-101的应用案例是一个重要的技术革新。这个转换过程涉及到两种主要的通信协议:Modbus和Ethernet IP。Modbus是一种串行通信协议,广泛应用于工业控制系统中。它简单、易于部署和维护…...