从0到1:C++ 开启游戏开发奇幻之旅(一)

目录
为什么选择 C++ 进行游戏开发
性能卓越
内存管理精细
跨平台兼容性强
搭建 C++ 游戏开发环境
集成开发环境(IDE)
Visual Studio
CLion
图形库
SDL(Simple DirectMedia Layer)
SFML(Simple and Fast Multimedia Library)
C++ 游戏开发基础知识
面向对象编程(OOP)
内存管理
C++ 标准库(STL)
为什么选择 C++ 进行游戏开发
在游戏开发的广袤领域中,编程语言的选择犹如基石,奠定着整个项目的成败与走向。C++ 凭借其卓越的特性,在众多编程语言中脱颖而出,成为游戏开发的中流砥柱,深受开发者们的青睐。
性能卓越
游戏,尤其是大型 3A 游戏,对性能有着近乎苛刻的要求。每一次画面的渲染、每一个物理效果的模拟、每一次玩家操作的响应,都需要在极短的时间内完成,以确保游戏的流畅运行和玩家的沉浸体验。C++ 在性能方面的表现堪称惊艳。它允许开发者直接对内存进行操作,这意味着可以精准地控制数据的存储和读取位置,大大提高了数据的访问速度。在处理大量的图形数据、物理模拟数据以及音频数据时,这种直接内存操作的能力显得尤为关键。例如,在渲染一个复杂的 3D 游戏场景时,C++ 能够快速地将顶点数据、纹理数据等传递给图形处理器(GPU),从而实现高效的图形渲染,使得游戏画面更加细腻、逼真,帧率更加稳定。
不仅如此,C++ 的代码经过编译后,会直接转化为机器码,运行时无需解释器或虚拟机的介入,这使得它的执行速度大幅提升。与一些需要在虚拟机环境中运行的编程语言相比,C++ 能够更充分地利用计算机硬件的性能,减少了额外的性能开销。这种高效的执行速度,让游戏能够以更高的帧率运行,为玩家带来更加流畅、丝滑的游戏体验。在激烈的游戏对战中,每一帧的流畅都可能影响着玩家的操作和决策,C++ 的高性能无疑为游戏的竞技性和娱乐性提供了坚实的保障。
内存管理精细
内存管理是游戏开发中至关重要的一环。游戏在运行过程中,需要动态地分配和释放大量的内存,以存储各种游戏资源,如角色模型、场景地图、纹理贴图等。如果内存管理不善,就会导致内存泄漏、内存碎片化等问题,进而影响游戏的性能和稳定性,甚至可能导致游戏崩溃。C++ 赋予了开发者手动管理内存的能力,通过 new 和 delete 操作符(或者 malloc 和 free 函数),开发者可以精确地控制内存的分配和释放时机。这对于游戏开发来说意义重大。在创建和销毁游戏对象(如角色、道具等)时,能够准确地分配和回收内存,避免了内存的浪费和泄漏。在一个大型的多人在线游戏中,同时存在着大量的玩家角色和游戏道具,精细的内存管理可以确保游戏在长时间运行过程中,内存的使用始终保持在合理的范围内,保证游戏的稳定运行。
此外,C++ 还提供了智能指针(如 std::shared_ptr、std::unique_ptr 等)等工具,帮助开发者更方便地管理内存,减少手动管理内存带来的错误风险。智能指针能够自动跟踪对象的引用计数,当对象不再被使用时,自动释放其所占用的内存,有效地避免了内存泄漏的问题。在处理复杂的游戏对象层次结构和资源管理时,智能指针的使用可以大大简化代码,提高代码的可读性和可维护性。
跨平台兼容性强
在当今多元化的游戏市场中,跨平台开发已成为游戏开发者们必须面对的需求。玩家们使用着各种各样的设备和操作系统来玩游戏,包括 Windows、MacOS、Linux 等桌面操作系统,以及 iOS、Android 等移动操作系统,还有各种游戏主机。C++ 作为一种跨平台的编程语言,能够在多个操作系统和硬件平台上编译和运行。这意味着开发者可以使用相同的代码库,针对不同的平台进行简单的适配和优化,就能够创建出多个版本的游戏,大大减少了开发和维护的工作量。
许多流行的游戏引擎,如 Unreal Engine、Unity(底层部分也有 C++ 支持)、Cocos2d - x 等,都是基于 C++ 构建的。这些引擎提供了强大的跨平台支持,开发者可以借助这些引擎,轻松地将游戏移植到不同的平台上,实现一次开发,多平台发布。以 Unreal Engine 为例,它使用 C++ 作为核心编程语言,通过其提供的一系列工具和接口,开发者可以方便地将游戏部署到 PC、游戏机、移动设备等多种平台上,并且能够充分利用各个平台的硬件特性,为玩家提供一致的游戏体验。这种跨平台的能力,不仅扩大了游戏的受众范围,还提高了游戏的商业价值。
搭建 C++ 游戏开发环境
“工欲善其事,必先利其器”,搭建一个高效的开发环境是 C++ 游戏开发的首要任务。一个好的开发环境能够极大地提高开发效率,减少开发过程中的错误和麻烦。下面我们将详细介绍常用的开发工具和库,以及它们的安装和配置步骤。
集成开发环境(IDE)
Visual Studio
Visual Studio 是一款由微软开发的功能强大的集成开发环境,广泛应用于 Windows 平台下的 C++ 开发。它提供了丰富的功能,包括代码编辑、调试、智能感知、代码分析等,能够帮助开发者高效地编写和调试代码。
安装步骤如下:
- 进入 Visual Studio 官网 (https://visualstudio.microsoft.com/),选择下载 Windows 版,并选择 Community 2019 社区版本(社区版对于个人开发者和小型团队是免费的,功能也非常齐全,足以满足大多数游戏开发的需求)进行下载,保存软件到电脑中。
- 双击运行下载的安装文件,弹出安装界面,选择 “使用 C++ 的桌面开发” 这一选项,如需其他,自行勾选。点击安装按钮开始安装。安装时间会依据网速、电脑设备等因素而有所不同,在此期间可以稍作等待,或者做一些其他的事情。
- 安装成功后提示重启,点击重启完成剩余配置。
- 在开始菜单找到 Visual Studio 2019 并且点击运行,弹出初始界面,点击 “创建新项目” 按钮 ,如果出现 C++ 项目模板选项,证明安装成功,并可以创建 C++ 项目。
CLion
CLion 是一款由 JetBrains 开发的跨平台 C++ 集成开发环境,它以其智能的代码编辑、强大的调试功能和对多种构建系统的支持而受到开发者的喜爱。无论是在 Windows、MacOS 还是 Linux 系统上,CLion 都能提供一致的高效开发体验。
安装步骤如下:
- 首先,从 CLion 官网 (https://www.jetbrains.com/clion/download/) 下载 Clion 安装文件。
- 下载完成后,解压缩安装文件,并运行 clion.exe 文件(在 Windows 系统下)。
- 进入 Clion 的安装界面,可以选择自定义安装选项或者选择默认选项,然后点击 “Next” 按钮。
- 勾选用户协议并继续。
- 在安装选项中,可以选择安装路径、添加图标等信息,然后点击 “Install” 按钮。
- 安装完成后,进行一些配置才能使用 Clion。在 Clion 主界面中,点击 “File” 菜单,然后选择 “Settings” 选项;找到 “Build, Execution, Deployment” 选项,并选择 “CMake” 选项;在 “CMake” 选项中,设置 CMake 和编译器的路径,以及其他相关选项;设置完成后,点击 “Apply” 按钮保存更改;最后,在 Clion 中创建一个新项目,并将代码添加到项目中。
图形库
SDL(Simple DirectMedia Layer)
SDL 是一个跨平台的多媒体库,它提供了对音频、键盘、鼠标、游戏杆和图形硬件的低级访问,非常适合用于开发 2D 游戏和多媒体应用程序。SDL 的设计目标是简单易用,同时又具有足够的灵活性和强大的功能,能够满足不同类型游戏的开发需求。
安装步骤如下(以 Windows 系统为例):
- 从 SDL 官网 (https://www.libsdl.org/download-2.0.php) 下载对应操作系统版本的 SDL2 库。
- 解压文件,将下载的压缩包解压至任意位置,得到类似如下的目录结构:
SDL2-2.26.1/ ├── include/ │ └── SDL2/ ├── lib/ │ ├── x86/ │ │ ├── SDL2.dll │ │ ├── SDL2main.lib │ │ └── SDL2.lib │ └── x64/ │ ├── SDL2.dll │ ├── SDL2main.lib │ └── SDL2.lib └── share/└── doc/└── SDL2/
- 配置开发环境(以 Visual Studio 为例):打开 Visual Studio,创建一个新的 C++ 项目,在项目中右键单击 “项目名称”,选择 “属性”;在左侧选择 “C/C++” -> “常规”,在 “附加包含目录” 中添加 SDL2-2.26.1/include 目录;在左侧选择 “链接器” -> “常规”,在 “附加库目录” 中添加 SDL2-2.26.1/lib/x64(如果是 x86 项目,则选择 x86 目录)目录;在左侧选择 “链接器” -> “输入”,在 “附加依赖项” 中添加 SDL2.lib 和 SDL2main.lib;将 SDL2-2.26.1/lib/x64(或 x86)目录下的 SDL2.dll 文件复制到项目的输出目录(通常是 Debug 或 Release 文件夹)。
SFML(Simple and Fast Multimedia Library)
SFML 也是一个跨平台的 C++ 多媒体库,它提供了简单直观的 API,用于处理图形、音频、网络和窗口等功能。SFML 的优势在于其简洁易用的接口和丰富的文档,对于初学者来说是一个很好的选择,能够快速上手并开发出有趣的 2D 游戏。
安装步骤如下(以 Windows 系统为例):
- 从 SFML 官网 (https://www.sfml-dev.org/download/sfml/2.6.0/) 下载适用于 Visual Studio 的 SFML 库。
- 解压文件,将下载的压缩包解压至任意位置,得到类似如下的目录结构:
SFML-2.6.0/ ├── include/ │ └── SFML/ ├── lib/ │ ├── libsfml-graphics-d.lib │ ├── libsfml-window-d.lib │ ├── libsfml-system-d.lib │ ├── libsfml-audio-d.lib │ ├── libsfml-network-d.lib │ ├── libsfml-graphics.lib │ ├── libsfml-window.lib │ ├── libsfml-system.lib │ ├── libsfml-audio.lib │ └── libsfml-network.lib └── share/└── sfml/├── cmake/└──...
- 配置开发环境(以 Visual Studio 为例):打开 Visual Studio,创建一个新的 C++ 项目,在项目中右键单击 “头文件”,选择 “添加现有项”,并选择 SFML-2.6.0/include 目录下的所有.hpp 文件,以添加 SFML 的头文件;在同样的位置右键单击 “源文件”,选择 “添加现有项”,并选择 SFML-2.6.0/lib 目录下与编译器相匹配的所有库文件(.lib 或.a)。例如,如果使用的是 64 位的编译器,就应该添加 SFML-2.6.0/lib/x64 下的所有库文件;在项目中右键单击,选择 “属性” 窗口。在左侧选择 “C/C++” -> “常规”,在 “附加包含目录” 中添加 SFML-2.6.0/include 目录;在左侧选择 “链接器” -> “常规”,在 “附加库目录” 中添加 SFML-2.6.0/lib 目录;在左侧选择 “链接器” -> “输入”,在 “附加依赖项” 中添加以下库文件(根据需要添加即可):sfml-graphics.lib、sfml-window.lib、sfml-system.lib、sfml-audio.lib、opengl32.lib、freetype.lib、winmm.lib、gdi32.lib ;如果使用的是静态库,应该添加 SFML_STATIC 编译器预处理器定义;将 SFML-2.6.0/bin 目录下的所有.dll 文件复制到项目的输出目录(通常是 Debug 或 Release 文件夹)。
C++ 游戏开发基础知识
在 C++ 游戏开发的旅程中,掌握一些基础知识是开启成功之门的关键。这些知识构成了游戏开发的基石,无论是小型的休闲游戏,还是大型的 3A 游戏,都离不开它们的支撑。下面,让我们深入探讨面向对象编程、内存管理以及 C++ 标准库在游戏开发中的重要性和应用。
面向对象编程(OOP)
面向对象编程(OOP)是 C++ 的核心特性之一,它为游戏开发带来了极大的便利和灵活性。OOP 主要包含封装、继承、多态这几个概念。
封装,就像是给游戏中的各种元素加上了一个 “保护壳”。在游戏中,每个角色都有自己的生命值、攻击力、防御力等属性,以及移动、攻击、防御等行为。通过封装,我们可以将这些属性和行为组合在一起,形成一个类。以《英雄联盟》为例,英雄 “艾克” 就是一个类的实例,他的生命值、攻击力等属性被封装在这个类中,而他的技能 “时间卷曲器”“相位俯冲” 等行为也通过类的成员函数来实现。外部代码不能直接访问这些属性,只能通过类提供的公共方法来操作,这就保证了数据的安全性和一致性。比如,其他玩家不能直接修改 “艾克” 的生命值,只能通过攻击等合法的游戏行为来影响他的生命值,这样就避免了数据被随意篡改,保证了游戏的公平性和稳定性。
继承,则是实现代码复用的重要手段。在游戏中,有很多相似的对象,比如不同类型的怪物,它们可能都有一些共同的属性和行为,如生命值、攻击力、移动等。我们可以创建一个基类,包含这些共同的属性和行为,然后让不同类型的怪物类继承这个基类。以《暗黑破坏神》系列游戏为例,游戏中有各种恶魔和怪物,它们都继承自一个 “怪物” 基类。“沉沦魔” 类继承自 “怪物” 基类,它不仅拥有 “怪物” 基类的基本属性和行为,还可以有自己特有的属性和行为,比如更灵活的移动方式、特殊的攻击技能等。通过继承,我们可以减少代码的重复编写,提高开发效率。当我们需要修改怪物的一些基本属性时,只需要在基类中进行修改,所有继承自这个基类的怪物类都会自动继承这些修改,大大方便了代码的维护和扩展。
多态,是指同一个操作作用于不同的对象,可以产生不同的结果。在游戏中,多态的应用非常广泛。以《鬼泣》系列游戏为例,游戏中的角色 “但丁” 可以使用不同的武器,如大剑、双枪等。每个武器都有自己的攻击方式和效果,但是我们可以通过一个统一的接口来调用这些武器的攻击方法。当 “但丁” 使用大剑时,调用的是大剑的攻击方法,产生大剑的攻击效果;当他使用双枪时,调用的是双枪的攻击方法,产生双枪的攻击效果。这就是多态的体现,它使得代码更加灵活和可扩展。当我们需要添加新的武器时,只需要创建一个新的武器类,实现统一的攻击接口,就可以轻松地将新武器融入游戏中,而不需要大量修改现有的代码。
内存管理
在 C++ 游戏开发中,内存管理是一个至关重要的环节,它直接影响着游戏的性能和稳定性。C++ 提供了两种主要的内存分配方式:堆栈内存和堆内存,它们各有特点和适用场景。
栈内存是一种自动分配和释放的内存区域,它的分配和释放速度非常快,就像在一个栈中放入和取出物品一样简单高效。函数的局部变量和函数调用信息通常存储在栈上。当函数被调用时,局部变量会在栈上自动分配内存空间;当函数执行结束时,这些局部变量所占用的内存会自动被释放。在一个简单的游戏函数中,比如计算角色移动距离的函数:
void calculateMoveDistance() {int speed = 5; // 局部变量speed存储在栈上int time = 10; // 局部变量time存储在栈上int distance = speed * time; // 局部变量distance存储在栈上// 函数执行结束,speed、time、distance所占用的栈内存自动释放
}
栈内存的优点是速度快、效率高,但是它的大小是有限的,并且变量的生命周期与函数的作用域紧密相关。如果在栈上分配过多的内存,或者在函数中创建了大型的局部数组,可能会导致栈溢出,从而使程序崩溃。
堆内存则是用于动态分配内存的区域,它由程序员手动控制内存的分配和释放。在游戏中,当我们需要创建一些动态的对象,如角色、道具等,并且这些对象的生命周期需要根据游戏的运行情况来动态管理时,就需要使用堆内存。以创建一个游戏角色为例:
class Character {
public:int health;int attackPower;// 其他属性和方法
};int main() {Character* character = new Character(); // 在堆上分配内存创建Character对象character->health = 100;character->attackPower = 20;// 使用character对象delete character; // 手动释放堆内存,避免内存泄漏return 0;
}
堆内存的优点是可以根据需要动态分配内存大小,灵活性高,但是它的分配和释放过程相对复杂,需要程序员手动操作,并且速度比栈内存慢。如果在堆上分配了内存,但是在使用完毕后没有及时释放,就会导致内存泄漏,随着游戏的运行,内存占用会越来越高,最终可能导致游戏卡顿甚至崩溃。
为了更好地管理堆内存,C++11 引入了智能指针(如std::shared_ptr、std::unique_ptr等)。智能指针能够自动跟踪对象的引用计数,当对象不再被使用时,自动释放其所占用的内存,有效地避免了内存泄漏的问题。以std::shared_ptr为例:
#include <memory>
#include <iostream>class Character {
public:int health;int attackPower;Character() : health(100), attackPower(20) {}~Character() { std::cout << "Character destroyed" << std::endl; }
};int main() {std::shared_ptr<Character> character = std::make_shared<Character>();// 使用character对象// 当character离开作用域时,其引用计数降为0,自动释放所指向的Character对象的内存return 0;
}
在这个例子中,std::shared_ptr会自动管理Character对象的生命周期,当character离开作用域时,它所指向的Character对象的内存会被自动释放,无需手动调用delete。智能指针的使用大大简化了内存管理,提高了代码的安全性和可维护性。
C++ 标准库(STL)
C++ 标准库(STL)是 C++ 编程中的强大工具集,它提供了丰富的容器和算法,在游戏开发中有着广泛的应用,能够大大提高开发效率。
STL 中的容器是存储和管理数据的重要工具,其中vector、list、map是比较常用的容器。vector是一个动态数组,它允许在运行时动态地调整大小,并且支持快速的随机访问。在游戏中,vector常用于存储游戏对象的集合,如游戏中的角色列表、道具列表等。以一个简单的射击游戏为例,我们可以使用vector来存储所有的敌人:
#include <vector>
#include <iostream>class Enemy {
public:int health;int attackPower;Enemy() : health(50), attackPower(10) {}
};int main() {std::vector<Enemy> enemies;for (int i = 0; i < 10; i++) {enemies.push_back(Enemy());}// 访问和操作enemies中的敌人for (size_t i = 0; i < enemies.size(); i++) {std::cout << "Enemy " << i << " health: " << enemies[i].health << std::endl;}return 0;
}
在这个例子中,vector可以方便地添加和访问敌人对象,并且在需要时自动调整大小,非常适合存储动态变化的游戏对象集合。
list是一个双向链表,它的特点是在链表的任何位置进行插入和删除操作都非常高效,但是不支持随机访问。在游戏中,当需要频繁地插入和删除元素时,list就派上了用场。比如在一个实时策略游戏中,单位的创建和销毁非常频繁,我们可以使用list来存储游戏中的单位:
#include <list>
#include <iostream>class Unit {
public:int health;int attackPower;Unit() : health(100), attackPower(20) {}
};int main() {std::list<Unit> units;units.push_back(Unit()); // 在链表尾部插入一个单位units.push_front(Unit()); // 在链表头部插入一个单位auto it = units.begin();++it; // 移动到第二个单位units.insert(it, Unit()); // 在第二个单位之前插入一个单位// 删除单位it = units.begin();units.erase(it); // 删除第一个单位// 遍历listfor (const auto& unit : units) {std::cout << "Unit health: " << unit.health << std::endl;}return 0;
}
在这个例子中,list的高效插入和删除操作使得它非常适合处理游戏中频繁变化的单位集合。
map是一个关联容器,它存储的是键值对,并且会根据键自动排序。在游戏中,map常用于存储需要根据某个键来查找对应值的数据,如游戏中的道具字典,我们可以使用道具的 ID 作为键,道具的详细信息作为值:
#include <map>
#include <string>
#include <iostream>class Item {
public:std::string name;int value;Item(const std::string& n, int v) : name(n), value(v) {}
};int main() {std::map<int, Item> items;items[1] = Item("Health Potion", 50); // 添加一个ID为1的道具items[2] = Item("Mana Potion", 30); // 添加一个ID为2的道具// 根据ID查找道具auto it = items.find(1);if (it!= items.end()) {std::cout << "Item name: " << it->second.name << ", value: " << it->second.value << std::endl;}return 0;
}
在这个例子中,map可以快速地根据道具 ID 查找到对应的道具信息,非常方便管理和查找游戏中的各种数据。
STL 中的算法也是游戏开发中不可或缺的工具,其中sort和find是比较常用的算法。sort算法用于对容器中的元素进行排序,在游戏中,经常需要对游戏对象进行排序,如根据角色的等级对角色进行排序,或者根据玩家的得分对玩家进行排名。以对玩家得分进行排序为例:
#include <vector>
#include <algorithm>
#include <iostream>struct Player {std::string name;int score;Player(const std::string& n, int s) : name(n), score(s) {}
};// 自定义比较函数,用于按得分从高到低排序
bool compareByScore(const Player& p1, const Player& p2) {return p1.score > p2.score;
}int main() {std::vector<Player> players;players.push_back(Player("Alice", 80));players.push_back(Player("Bob", 90));players.push_back(Player("Charlie", 70));// 对玩家按得分进行排序std::sort(players.begin(), players.end(), compareByScore);// 输出排序后的玩家列表for (const auto& player : players) {std::cout << "Player: " << player.name << ", Score: " << player.score << std::endl;}return 0;
}
在这个例子中,std::sort算法可以方便地对玩家列表进行排序,使得玩家按照得分从高到低排列。
find算法用于在容器中查找指定的元素,在游戏中,经常需要查找某个特定的游戏对象,如查找某个 ID 对应的角色,或者查找某个位置的道具。以查找某个 ID 对应的角色为例:
#include <vector>
#include <algorithm>
#include <iostream>class Character {
public:int id;std::string name;Character(int i, const std::string& n) : id(i), name(n) {}
};int main() {std::vector<Character> characters;characters.push_back(Character(1, "Warrior"));characters.push_back(Character(2, "Mage"));characters.push_back(Character(3, "Rogue"));// 查找ID为2的角色auto it = std::find_if(characters.begin(), characters.end(), [](const Character& c) {return c.id == 2;});if (it!= characters.end()) {std::cout << "Found Character: " << it->name << std::endl;} else {std::cout << "Character not found" << std::endl;}return 0;
}
在这个例子中,std::find_if算法可以在characters容器中查找 ID 为 2 的角色,如果找到则输出角色的名字,否则输出提示信息。
相关文章:
从0到1:C++ 开启游戏开发奇幻之旅(一)
目录 为什么选择 C 进行游戏开发 性能卓越 内存管理精细 跨平台兼容性强 搭建 C 游戏开发环境 集成开发环境(IDE) Visual Studio CLion 图形库 SDL(Simple DirectMedia Layer) SFML(Simple and Fast Multim…...
基于Flask的哔哩哔哩综合指数UP榜单数据分析系统的设计与实现
【Flask】基于Flask的哔哩哔哩综合指数UP榜单数据分析系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统旨在通过大数据分析和数据挖掘技术,结合Flask轻量级We…...
在php中怎么打开OpenSSL
(点击即可进入聊天助手) 背景 在使用php做一些项目时,有用到用户邮箱注册等,需要开启openssl的能力 在php系统中openssl默认是关闭状态的,在一些低版本php系统中,有的甚至需要在服务器终端后台,手动安装 要打开OpenSSL扩展,需要进行以下步骤 …...
oracle 分区表介绍
oracle 分区表介绍 Oracle 分区表是一个非常强大的数据库功能,可以将一个大的表分割成多个更小、更易管理的块(分区)。这种分区结构在处理大规模数据时非常有用,因为它能改善性能、简化维护和管理,并支持高效的数据存取…...
wxwidgets直接获取系统图标,效果类似QFileIconProvider
目前只做了windows版本,用法类似QFileIconProvider // 头文件 #ifndef WXFILEICONPROVIDER_H #define WXFILEICONPROVIDER_H#include <wx/wx.h> #include <wx/icon.h> #include <wx/image.h> #include <wx/bmpcbox.h> // Include for wxB…...
Arduino大师练成手册 -- 控制 PN532 NFC 模块
要在 Arduino 上控制 PN532 NFC 模块,你可以按照以下步骤进行: 硬件连接 VCC:连接到 Arduino 的 3.3V 引脚。 GND:连接到 Arduino 的 GND 引脚。 SDA:连接到 Arduino 的 SDA 引脚(通常是 A4)…...
解决日志中 `NOT NULL constraint failed` 异常的完整指南
在开发和运维过程中,日志是我们排查问题的重要工具。然而,当日志中出现类似 NOT NULL constraint failed 的异常时,往往意味着数据库约束与代码逻辑不匹配。本文将详细分析此类问题的原因,并提供完整的解决方案。 © ivwdcwso (ID: u012172506) 问题描述 在同步 AWS …...
C动态库的生成与在Python和QT中的调用方法
目录 一、动态库生成 1)C语言生成动态库 2)c类生成动态库 二、动态库调用 1)Python调用DLL 2)QT调用DLL 三、存在的一些问题 1)python调用封装了类的DLL可能调用不成功 2)DLL格式不匹配的问题 四、…...
UE求职Demo开发日志#7 强化属性完善
1 实现思路设计 定义一个结构体记录技能树一个单元的信息,命名为FStrengthenCellInfo,一个TArray记录技能树整体信息,需要以下信息: 1.TArray前置技能index 2.FString 描述文本 3.TArray<FMyItemInfo>激活需要的物品ID和…...
Day35:字符串的大小写转换
在 Python 中,字符串的大小写转换是一个常见的操作,它可以帮助我们快速地将字符串中的字母从大写转换为小写,或者从小写转换为大写。Python 提供了多种方法来进行字符串大小写的转换,包括 upper()、lower()、capitalize()、title(…...
喜报丨迪捷软件入选2025年浙江省“重点省专”
根据《浙江省经济和信息化厅 浙江省财政厅关于进一步支持专精特新中小企业高质量发展的通知》(浙经信企业〔2024〕232号)有关要求,经企业自主申报、地方推荐、材料初审以及专家评审等程序,浙江省经济和信息化厅发布了2025年浙江省…...
深度剖析 PyTorch框架:从基础概念到高级应用的深度学习之旅!
目录 一、引言 二、PyTorch 简介 (一)诞生背景与发展历程 (二)核心特点 三、PyTorch 基础概念 (一)张量(Tensor):数据的基石 (二)自动微分&…...
基于C++的DPU医疗领域编程初探
一、大型医院数据处理困境与 DPU 的崛起 在数字化浪潮的席卷下,医疗行业正经历着深刻变革,大型医院作为医疗服务的核心枢纽,积累了海量的数据,涵盖患者的基本信息、诊断记录、检验报告、影像资料等多个维度。这些数据不仅规模庞大,而且增长速度迅猛,传统的中央处理器(C…...
Linux 执行 fdisk -l 出现 GPT PMBR 大小不符 解决方法
目录 前言1. 问题所示2. 原理分析3. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 1. 问题所示 执行fdisk -l的时候出现如下提示: [root@VMS-Centos-test1 ~]# fdisk -l GPT PMBR 大小不符(419430399 != 4294967295),将用写入予以更正…...
图漾相机搭配VisionPro使用简易教程
1.下载并安装VisionPro软件 请自行下载VisonPro软件。 VisionPro 9.0 /9.5/9.6版本经测试,可正常打开图漾相机,建议使用图漾测试过的版本。 2.下载PercipioCameraForVisionPro软件包 使用浏览器下载:https://gitee.com/percipioxyz/camport…...
第一届“启航杯”网络安全挑战赛WP
misc PvzHE 去这个文件夹 有一张图片 QHCTF{300cef31-68d9-4b72-b49d-a7802da481a5} QHCTF For Year 2025 攻防世界有一样的 080714212829302316092230 对应Q 以此类推 QHCTF{FUN} 请找出拍摄地所在位置 柳城 顺丰 forensics win01 这个软件 云沙盒分析一下 md5 ad4…...
大模型训练策略与架构优化实践指南
标题:大模型训练策略与架构优化实践指南 文章信息摘要: 该分析全面探讨了大语言模型训练、架构选择、部署维护等关键环节的优化策略。在训练方面,强调了pre-training、mid-training和post-training的不同定位与目标;在架构选择上…...
新电脑安装系统找不到硬盘原因和解决方法来了
有不少网友反馈新电脑采用官方u盘方式装win10或win100出现找不到硬盘是怎么回事?后来研究半天发现是bios中开启了rst(vmd)模式。如果关闭rst模式肯定是可以安装的,但这会影响硬盘性能,有没有办法解决开启rst模式的情况安装win10或win11呢&…...
【Linux】21.基础IO(3)
文章目录 3. 动态库和静态库3.1 静态库与动态库3.2 静态库的制作和使用原理3.3 动态库的制作和使用原理3.3.1 动态库是怎么被加载的 3.4 关于地址 3. 动态库和静态库 3.1 静态库与动态库 静态库(.a):程序在编译链接的时候把库的代码链接到可…...
深度学习算法:从基础到实践
简介 深度学习作为人工智能领域的一个重要分支,近年来在多个领域取得了显著的成就。本文将从基础概念出发,探讨深度学习算法的核心原理,并介绍一些实际应用案例。 深度学习算法的核心概念 深度学习算法基于人工神经网络,通过构…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...
【多线程初阶】单例模式 指令重排序问题
文章目录 1.单例模式1)饿汉模式2)懒汉模式①.单线程版本②.多线程版本 2.分析单例模式里的线程安全问题1)饿汉模式2)懒汉模式懒汉模式是如何出现线程安全问题的 3.解决问题进一步优化加锁导致的执行效率优化预防内存可见性问题 4.解决指令重排序问题 1.单例模式 单例模式确保某…...
