C++之fmt库介绍和使用(1)
C++之fmt库介绍与使用(1)
Author: Once Day Date: 2025年5月12日
一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…
漫漫长路,有人对你微笑过嘛…
全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客
参考文章:
- Get Started - {fmt}
- fmtlib/fmt: A modern formatting library
文章目录
- C++之fmt库介绍与使用(1)
- 1. 介绍
- 1.1 概述
- 1.2 性能对比
- 1.3 编译时间和代码膨胀
- 1.4 CMake编译
- 2. API介绍
- 2.1 基础API
- 2.2 格式化用户定义类型
- 2.3 编译时检测
- 2.4 命名参数(Named Arguments)
- 2.5 类型擦除
- 2.6 兼容性
1. 介绍
1.1 概述
fmtlib是一个现代化的C++格式化库,它提供了一种安全、高效、灵活的方式来格式化和输出文本。该库由Victor Zverovich开发,旨在替代C++标准库中的iostream和printf等传统格式化方法。
使用fmtlib非常简单,只需包含fmt/core.h
头文件,然后使用fmt::format()
函数或fmt::print()
函数即可。例如:
#include <fmt/core.h>int main() {std::string name = "Alice";int age = 18;fmt::print("Her name is {} and she is {} years old.\n", name, age);return 0;
}
以上代码将输出:“Her name is Alice and she is 18 years old.”
fmtlib具有具有如下的特性:
(1)安全性:受 Python 格式化功能的启发,{fmt} 为printf
系列函数提供了安全的替代方案。格式字符串中的错误在 C 语言中是常见的漏洞来源,而在 {fmt} 中,这类错误会在编译时被报告出来。
fmt::format("{:d}", "I am not a number");
上述代码会产生编译时错误,因为d
不是字符串的有效格式说明符。像fmt::format
这样的 API 通过自动内存管理来防止缓冲区溢出错误。
(2)可扩展性:{fmt} 开箱即支持大多数标准类型的格式化,包括所有容器、日期和时间。例如:
fmt::print("{}", std::vector{1, 2, 3});
上述代码会以类似 JSON 的格式打印向量:
[1, 2, 3]
你可以让自己定义的类型支持格式化,甚至还能对它们进行编译时检查。
(3)性能:{fmt} 比输入输出流(iostreams)和sprintf
快 20 - 30 倍,在数值格式化方面表现尤为突出。
{fmt} 库尽量减少动态内存分配,并且可以选择将格式字符串编译为最优代码。
(4)Unicode 支持:{fmt} 在主要操作系统上通过 UTF - 8 和char
字符串提供可移植的 Unicode 支持。例如:
fmt::print("Слава Україні!");
上述代码在 Linux、macOS 甚至 Windows 控制台上都能正确打印,而无需考虑代码页问题。
{fmt} 默认与区域设置无关,但你也可以选择进行本地化格式化,{fmt} 能够使其与 Unicode 协同工作,解决了标准库中存在的相关问题。
(5)快速编译:该库广泛使用类型擦除技术来实现快速编译。fmt/base.h
提供了一部分 API,其包含的依赖关系极少,并且具备足够的功能来替代所有*printf
的使用场景。
使用 {fmt} 的代码编译速度通常比等效的输入输出流代码快几倍。虽然printf
的编译速度仍然更快,但两者之间的差距正在逐渐缩小。
(6)较小的二进制体积:类型擦除技术还用于防止模板膨胀,从而生成紧凑的单次调用二进制代码。例如,调用带单个参数的fmt::print
仅需几条指令,尽管它增加了运行时安全性,但其二进制体积与printf
相当,并且比等效的输入输出流代码小得多。
该库本身的二进制体积较小,像浮点格式化这样的一些组件可以被禁用,以便在资源受限的设备上进一步减小其体积。
(7)可移植性:{fmt} 拥有一个小巧且自包含的代码库,其核心仅由三个头文件组成,并且没有外部依赖。
该库具有高度的可移植性,仅需要 C++11 的一小部分特性,这些特性在 GCC 4.9、Clang 3.4、MSVC 19.10(2017)及更高版本中均可用。如果编译器和标准库支持更新的特性,{fmt} 会加以利用,从而启用更多功能。
在可能的情况下,格式化函数的输出在各个平台上保持一致。
在可能的情况下,格式化函数的输出在各个平台上保持一致。
(8)开源:{fmt} 是 GitHub 上排名前一百的开源 C++ 库,拥有数百名贡献者。
该库基于宽松的 MIT 许可证分发,被许多开源项目所依赖,包括 Blender、PyTorch、苹果的 FoundationDB、Windows Terminal、MongoDB 等。
fmtlib的主要特点包括:
- 简单的 格式化 API,支持位置参数以方便本地化。
- 实现了 C++20 的
std::format
和 C++23 的std::print
。 - 格式化字符串语法 类似于 Python 的 format。
- 快速的 IEEE 754 浮点数格式化器,使用 Dragonbox 算法,保证正确的舍入、最短表示和往返转换。
- 可移植的 Unicode 支持。
- 安全的 printf 实现,包括支持位置参数的 POSIX 扩展。
- 可扩展性:支持用户自定义类型。
- 高性能:比常见的标准库实现(如
(s)printf
、iostreams、to_string
)更快。 - 安全性:该库是完全类型安全的,格式化字符串中的错误可以在编译时报告,自动内存管理可防止缓冲区溢出错误。
- 易用性:代码库小巧且自包含,无外部依赖,采用宽松的 MIT 许可证。
- 可移植性:跨平台输出一致,支持较旧的编译器。
- 代码干净,即使在高警告级别(如
-Wall -Wextra -pedantic
)下也无警告。 - 默认与区域设置无关。
- 可通过
FMT_HEADER_ONLY
宏启用可选的仅头文件配置。
1.2 性能对比
{fmt}是基准测试中最快的方法,比printf快约20%。
Library | Method | Run Time, s |
---|---|---|
libc | printf | 0.91 |
libc++ | std::ostream | 2.49 |
{fmt} 9.1 | fmt::print | 0.74 |
Boost Format 1.80 | boost::format | 6.26 |
Folly Format | folly::format | 1.87 |
上述结果是在macOS 12.6.1上使用clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT编译tinyformat_test.cpp,并取三次运行中的最佳结果生成的。
在测试中,格式字符串%0.10f:%04d:%+g:%s:%p:%c:%%\n
或等效字符串被填充2,000,000次,输出被发送到/dev/null
;
在IEEE754浮点数和双精度格式化(dtoa-benchmark)方面,{fmt}比std::ostringstream和sprintf快20-30倍,并且比double-conversion和ryu更快:
1.3 编译时间和代码膨胀
format-benchmark中的脚本bloat-test.py测试了非平凡项目的编译时间和代码膨胀。它生成100个翻译单元,并在每个单元中使用printf()或其替代方法五次,以模拟一个中等规模的项目。生成的可执行文件大小和编译时间(Apple clang version 15.0.0 (clang-1500.1.0.2.5),macOS Sonoma,三次中的最佳结果)如下表所示。
优化构建(-O3):
Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
---|---|---|---|
printf | 1.6 | 54 | 50 |
IOStreams | 25.9 | 98 | 84 |
fmt 83652df | 4.8 | 54 | 50 |
tinyformat | 29.1 | 161 | 136 |
Boost Format | 55.0 | 530 | 317 |
{fmt}编译速度快,在每次调用的二进制大小方面与printf相当(在此系统上在舍入误差范围内)。
非优化构建:
Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
---|---|---|---|
printf | 1.4 | 54 | 50 |
IOStreams | 23.4 | 92 | 68 |
{fmt} 83652df | 4.4 | 89 | 85 |
tinyformat | 24.5 | 204 | 161 |
Boost Format | 36.4 | 831 | 462 |
libc、lib(std)c++和libfmt都作为共享库进行链接,以仅比较格式化函数的开销。Boost Format是一个仅包含头文件的库,因此它不提供任何链接选项。
1.4 CMake编译
{fmt} 提供了两个 CMake 目标:fmt::fmt
用于编译库,fmt::fmt-header-only
用于仅包含头文件的库。为了缩短构建时间,建议使用编译库。
在 CMake 中使用 {fmt} 主要有三种方式:
FetchContent:从 CMake 3.11 开始,可以使用FetchContent
在配置时自动下载 {fmt} 作为依赖项:
include(FetchContent)FetchContent_Declare(fmtGIT_REPOSITORY https://github.com/fmtlib/fmtGIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1FetchContent_MakeAvailable(fmt)target_link_libraries(<your-target> fmt::fmt)
已安装版本:可以在CMakeLists.txt
文件中查找并使用已安装的 {fmt} 版本,如下所示:
find_package(fmt)
target_link_libraries(<your-target> fmt::fmt)
嵌入方式:可以将 {fmt} 的源文件目录添加到项目中,并在CMakeLists.txt
文件中包含它:
add_subdirectory(fmt)
target_link_libraries(<your-target> fmt::fmt)
安装发布版本:要在 Ubuntu 的 Linux 发行版上安装 {fmt},请使用以下命令:
apt install libfmt-dev
从源代码构建:CMake 通过生成原生的 makefile 或项目文件来工作,这些文件可以在你选择的编译器环境中使用。典型的工作流程如下:
mkdir build # 创建一个目录来存放构建输出。
cd build
cmake .. # 生成原生构建脚本。
常见的Cmake编译构建选项如下所示:
# 编译 thirdparty/fmt-11.1.4
# FMT_MASTER_PROJECT=OFF 非主项目
# FMT_UNICODE=OFF 不支持Unicode
$SOURCE_DIR/devops/scripts/cmake_build.sh thirdparty/fmt-11.1.4 \-DFMT_MASTER_PROJECT=OFF \-DFMT_UNICODE=OFF
2. API介绍
{fmt} 库的 API 由以下组件构成:
- fmt/base.h:基础 API,提供面向 char/UTF-8 的主要格式化函数,具备 C++20 编译时检查功能,且依赖极少。
- fmt/format.h:包含 fmt::format 及其他格式化函数,同时提供本地化支持。
- fmt/ranges.h:用于格式化范围(ranges)和元组(tuples)。
- fmt/chrono.h:实现日期和时间的格式化。
- fmt/std.h:为标准库类型提供格式化器。
- fmt/compile.h:用于格式化字符串编译。
- fmt/color.h:提供终端颜色和文本样式功能。
- fmt/os.h:包含系统相关 API。
- fmt/ostream.h:提供对 std::ostream 的支持。
- fmt/args.h:支持动态参数列表。
- fmt/printf.h:提供安全的 printf 功能。
- fmt/xchar.h:提供可选的 wchar_t 支持。
该库提供的所有函数和类型都位于 fmt 命名空间中,而宏则以 FMT_ 为前缀。
2.1 基础API
fmt/base.h
定义了基础 API,它为 char
/UTF-8 提供主要的格式化函数,并具备 C++20 编译时检查功能。为了优化编译速度,它的头文件依赖被减至最少。这个头文件仅在将 {fmt} 作为库使用时(默认方式)才有优势,在仅头文件模式下并无作用。它还为以下类型提供了格式化器特化:
int
,long long
unsigned
,unsigned long long
float
,double
,long double
bool
char
const char*
,fmt::string_view
const void*
以下函数使用的格式字符串语法类似于 Python 中 str.format
的语法。它们接受 fmt
和 args
作为参数:
fmt
是一个格式字符串,包含普通文本和用花括号{}
包围的替换字段。这些字段会在结果字符串中被格式化为对应的参数。fmt::format_string
是一种格式字符串,它可以从字符串字面量或constexpr
字符串隐式构造,并在 C++20 中进行编译时检查。若要传递运行时格式字符串,需将其包装在fmt::runtime
中。args
是一个参数列表,表示要格式化的对象。
除非另有说明,I/O 错误会以 std::system_error
异常的形式报告。
template <typename... T>
void print(format_string<T...> fmt, T&&... args);fmt::print("The answer is {}.", 42);
根据 fmt
中的规范格式化 args
,并将输出写入标准输出(stdout
)。
template <typename... T>
void print(FILE* f, format_string<T...> fmt, T&&... args);fmt::print(stderr, "Don't {}!", "panic");
根据 fmt
中的规范格式化 args
,并将输出写入文件 f
。
template <typename... T>
void println(format_string<T...> fmt, T&&... args);
根据 fmt
中的规范格式化 args
,将输出写入标准输出(stdout
),并在末尾添加一个换行符。
template <typename... T>
void println(FILE* f, format_string<T...> fmt, T&&... args);
根据 fmt
中的规范格式化 args
,将输出写入文件 f
,并在末尾添加一个换行符。
template <typename OutputIt, typename... T>
auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args) -> remove_cvref_t<OutputIt>;auto out = std::vector<char>();
fmt::format_to(std::back_inserter(out), "{}", 42);
根据 fmt
中的规范格式化 args
,将结果写入输出迭代器 out
,并返回指向输出范围末尾之后的迭代器。format_to
不会追加终止空字符。
template <typename OutputIt, typename... T>
auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>;
根据 fmt
中的规范格式化 args
,将结果的最多 n
个字符写入输出迭代器 out
,并返回总输出大小(未截断)和指向输出范围末尾之后的迭代器。format_to_n
不会追加终止空字符。
template <typename OutputIt>
struct format_to_n_result;
OutputIt out;
:指向输出范围末尾之后的迭代器。size_t size;
:总输出大小(未截断)。
template <typename... T>
auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t;
返回 format(fmt, args...)
输出的字符数。
2.2 格式化用户定义类型
{fmt} 库为许多标准 C++ 类型提供了格式化器。有关范围(ranges)和元组(包括 std::vector
等标准容器)的格式化器,请参阅 fmt/ranges.h
;有关日期和时间的格式化器,请参阅 fmt/chrono.h
;有关其他标准库类型的格式化器,请参阅 fmt/std.h
。
有两种方法可以使自定义类型支持格式化:提供 format_as
函数或特化 formatter
结构体模板。
如果你希望将自定义类型按照另一种具有相同格式说明符的类型进行格式化,可以使用 format_as
方法。该函数应接受你的类型对象,并返回一个可格式化类型的对象。它应与你的类型定义在同一命名空间中。
#include <fmt/format.h>namespace kevin_namespacy {enum class film {house_of_cards, american_beauty, se7en = 7
};auto format_as(film f) { return fmt::underlying(f); }}int main() {fmt::print("{}\n", kevin_namespacy::film::se7en); // 输出: 7
}
下面这种方法更复杂,但能完全控制解析和格式化过程。要使用此方法,需为你的类型特化 formatter
结构体模板,并实现 parse
和 format
方法。
推荐的定义格式化器的方法是通过继承或组合复用现有的格式化器。这样可以支持标准格式说明符而无需自己实现。例如:
// color.h:
#include <fmt/base.h>enum class color {red, green, blue};template <> struct fmt::formatter<color>: formatter<string_view> {// parse 方法继承自 formatter<string_view>。auto format(color c, format_context& ctx) const-> format_context::iterator;
};// color.cc:
#include "color.h"
#include <fmt/format.h>auto fmt::formatter<color>::format(color c, format_context& ctx) const-> format_context::iterator {string_view name = "unknown";switch (c) {case color::red: name = "red"; break;case color::green: name = "green"; break;case color::blue: name = "blue"; break;}return formatter<string_view>::format(name, ctx);
}
注意,formatter<string_view>::format
定义在 fmt/format.h
中,因此必须在源文件中包含该头文件。由于 parse
方法继承自 formatter<string_view>
,它将识别所有字符串格式规范,例如:
fmt::format("{:>10}", color::blue)
将返回 " blue"
。
一般来说,格式化器具有以下形式:
template <> struct fmt::formatter<T> {// 解析格式说明符并将其存储在格式化器中。//// [ctx.begin(), ctx.end()) 是一个可能为空的字符范围,// 包含从要解析的格式规范开始的格式字符串的一部分,例如在//// fmt::format("{:f} continued", ...);//// 该范围将包含 "f} continued"。格式化器应解析说明符直到 '}' 或范围结束。// 在这个例子中,格式化器应解析 'f' 说明符并返回指向 '}' 的迭代器。constexpr auto parse(format_parse_context& ctx)-> format_parse_context::iterator;// 使用存储在格式化器中的已解析格式规范格式化 value,// 并将输出写入 ctx.out()。auto format(const T& value, format_context& ctx) const-> format_context::iterator;
};
建议至少支持适用于整个对象的填充(fill)、对齐(align)和宽度(width)选项,它们的语义应与标准格式化器中的相同。
你还可以为类层次结构编写格式化器:
// demo.h:
#include <type_traits>
#include <fmt/core.h>struct A {virtual ~A() {}virtual std::string name() const { return "A"; }
};struct B : A {virtual std::string name() const { return "B"; }
};template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_base_of_v<A, T>, char>> :fmt::formatter<std::string> {auto format(const A& a, format_context& ctx) const {return formatter<std::string>::format(a.name(), ctx);}
};// demo.cc:
#include "demo.h"
#include <fmt/format.h>int main() {B b;A& a = b;fmt::print("{}", a); // 输出: B
}
注意:不允许同时提供格式化器特化和 format_as
重载。
上下文类型定义:
template <typename Char>
using basic_format_parse_context = parse_context<Char>;class context;context(iterator out, format_args args, detail::locale_ref loc);
构造一个上下文对象。对象中存储了对参数的引用,因此请确保这些参数具有适当的生命周期。
using format_context = context;
2.3 编译时检测
在支持 C++20 consteval
的编译器上,编译时格式字符串检查默认是启用的。在较旧的编译器上,你可以使用fmt/format.h
中定义的FMT_STRING
宏来替代。
和 Python 的str.format
以及普通函数一样,{fmt} 允许存在未使用的参数。
template <typename Char, typename... T>
using basic_format_string = basic_fstring<Char, T...>;template <typename... T>
using format_string = typename fstring<T...>::t;auto runtime(string_view s) -> runtime_format_string<>;
创建一个运行时格式字符串。
// 在运行时而不是编译时检查格式字符串。
fmt::print(fmt::runtime("{:d}"), "I am not a number");
2.4 命名参数(Named Arguments)
template <typename Char, typename T>
auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T>;
返回一个用于格式化函数的命名参数。它只能在调用格式化函数时使用。
fmt::print("The answer is {answer}.", fmt::arg("answer", 42));
目前,编译时检查不支持命名参数。
2.5 类型擦除
你可以创建自己的具有编译时检查和较小二进制体积的格式化函数,例如:
#include <fmt/format.h>void vlog(const char* file, int line,fmt::string_view fmt, fmt::format_args args) {fmt::print("{}: {}: {}", file, line, fmt::vformat(fmt, args));
}template <typename... T>
void log(const char* file, int line,fmt::format_string<T...> fmt, T&&... args) {vlog(file, line, fmt, fmt::make_format_args(args...));
}#define MY_LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)MY_LOG("invalid squishiness: {}", 42);
注意,与完全参数化的版本相比,vlog
没有对参数类型进行参数化,这提高了编译速度并减小了二进制代码大小。
template <typename Context, typename... T, int NUM_ARGS, int NUM_NAMED_ARGS, unsigned long long DESC>
constexpr auto make_format_args(T&... args) -> detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>;
构造一个存储对参数的引用的对象,并且该对象可以隐式转换为 format_args
。Context
可以省略,在这种情况下它默认为 context
。
template <typename Context>
class basic_format_args;void vlog(fmt::string_view fmt, fmt::format_args args); // 正确
fmt::format_args args = fmt::make_format_args(); // 悬空引用
格式化参数集合的视图。为了避免生命周期问题,它应该仅用作类型擦除函数(如 vformat
)中的参数类型:
constexpr basic_format_args(const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s);
从 format_arg_store
构造一个 basic_format_args
对象。
constexpr basic_format_args(const format_arg* args, int count, bool has_named);
从动态参数列表构造一个 basic_format_args
对象。
auto get(int id) -> format_arg;
返回具有指定 id
的参数。
using format_args = basic_format_args<context>;template <typename Context>
class basic_format_arg;auto visit(Visitor&& vis) -> decltype(vis(0));
根据参数类型调用适当的 visit
方法来访问参数。例如,如果参数类型是 double
,则将使用 double
类型的值调用 vis(value)
。
2.6 兼容性
template <typename Char>
class basic_string_view;
basic_string_view
是针对 C++17 之前版本实现的 std::basic_string_view
。它提供了该类型 API 的一个子集。即使存在 std::basic_string_view
,fmt::basic_string_view
也会被用于格式字符串,这样做是为了防止在库和客户端代码使用不同的 -std
选项进行编译时出现问题(不推荐使用不同的 -std
选项)。
constexpr basic_string_view(const Char* s, size_t count);
从一个 C 字符串和一个大小构造一个字符串引用对象。
basic_string_view(const Char* s);
从一个 C 字符串构造一个字符串引用对象。
basic_string_view(const S& s);
从一个 std::basic_string
或 std::basic_string_view
对象构造一个字符串引用。
constexpr auto data() -> const Char*;
返回指向字符串数据的指针。
constexpr auto size() -> size_t;
返回字符串的大小。
using string_view = basic_string_view<char>;
相关文章:
C++之fmt库介绍和使用(1)
C之fmt库介绍与使用(1) Author: Once Day Date: 2025年5月12日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客 …...
嵌入式自学第二十一天(5.14)
gdb逻辑调试器: gcc 调试,发行版 gcc -g 调试版本,体积大,有源码。 一般调试:gdb a.out b n.c:行数 :设置断点,运行到这个位置,程序暂停。(可以直接加行数) r运行 n执行下…...
位与运算
只有当除数是 2 的幂次方(如 2、4、8、16...)时,取模运算才可以转换为位运算。 int b 19;int a1 b % 16; // 传统取模运算int a2 b & 15; // 位运算替代取模printf("b %d\n", b);printf("b %% 8 %d\n",…...
SparkSQL操作Mysql(2)
创建数据库和表 我们去创建一个新的数据库,数据表,并插入一条数据。 参考代码如下: -- 创建数据库 CREATE DATABASE spark; -- 使用数据库 USE spark; -- 创建表 create table person(id int, name char(20), age int); -- 插入示例数…...
Linux 中 open 函数的本质与细节全解析
一、open简介 在 Linux 下,一切皆文件。而对文件的读写,离不开文件的“打开”操作。虽然 C 语言标准库提供了方便的 fopen,但更底层、更强大的是系统调用 open,掌握它能让你对文件系统控制更细致,在系统编程、驱动开发…...
对抗系统熵增:从被动救火到主动防御的稳定性实战
📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)、(进阶篇)、(架构篇)清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、…...
高速系统设计实例设计分析二
6.6 仿真约束的生成和实施 进行到这一步,我们已经完成了对实例进行仿真的所有条件的设置,包括对板子的设计要求分析和预布局处理。虽然从技术上讲,我们可以开始进行仿真分析并生成设计的约束,但是根据作者的工作经验,…...
AUTOSAR图解==>AUTOSAR_SWS_V2XGeoNetworking
AUTOSAR V2X GeoNetworking 模块分析 车联网地理网络协议解析与实现 目录 1. 概述2. 模块架构分析 2.1 AUTOSAR V2X GeoNetworking 在BSW架构中的位置 2.1.1 架构层次说明2.1.2 模块间关系 2.2 V2X GeoNetworking 模块内部组件结构 2.2.1 核心组件2.2.2 接口说明 3. 消息处理…...
在 Rocky Linux 上手动安装 zsh
目录 🧩 一、准备:检查是否已经安装Zsh 🛠️ 二、从源码安装 Zsh(推荐方式) 1. 下载 Zsh 源码 2. 解压源码 3. 配置安装路径(到你的 home 目录下) 4. 编译并安装 🧪 三、测试…...
Vector和list
一、Vector和list的区别——从“它们是什么”到“区别在哪儿” 1. 它们是什么? Vector:类似于一排排整齐的书架(数组),存放元素时,元素排成一条线,连续存储。可以很快通过编号(索引…...
人工智能外呼系统:重构智能交互的全维度进化
在数字化浪潮席卷全球的今天,人工智能外呼系统正以其颠覆性的技术革新,重新定义企业与客户的沟通范式。这一融合语音识别、自然语言处理与机器学习的智能系统,不仅实现了从 “机械应答” 到 “智慧交互” 的跨越,更在金融、医疗、…...
嵌入式培训之数据结构学习(三)gdb调试
一、gdb调试 (一)一般调试步骤与命令 1、gcc -g (调试版本,内含调试信息与源码;eg:gcc -g main.c linklist.c) 2、gdb a.out(调试可执行文件,eg:gdb ./a.o…...
元宇宙赛道新势力:成都芯谷产业园创新业务如何重构产业格局
成都芯谷产业园在元宇宙有啥新搞头?看看它的创新业务怎么改变行业! 成都芯谷产业园在元宇宙赛道上的创新业务,核心在于系统性构建一个开放、协同、高效的元宇宙创新生态系统,以此重构产业格局。这并非简单的企业物理聚集…...
Java 日期解析与格式化:从标准格式到自然语言解析
使用 Java 搭配 Apache Commons Lang3 和 Natty 库,实现灵活高效的日期解析与格式化。 一、背景 将不同格式的日期统一成一个格式。日期格式可能有以下几种类型: 标准格式:2024-02-28、14/05/2022、2002年5月6日非英文月份缩写:…...
【windows server脚本每天从网络盘复制到本地】
windows server脚本每天从网络盘复制到本地 调试模板 echo off :: 显示详细操作 echo echo 执行批处理文件:文件复制任务 echo :: 配置参数 set sourcePath\\network_drive\shared_folder :: 网络盘路径 set destinationPathC:\LocalBackup :: 本地保…...
GraphPad Prism简介、安装与工作界面
GraphPad Prism图表可视化与统计数据分析(视频教学版) - 商品搜索 - 京东 1.1 GraphPad Prism简介 GraphPad Prism 将科学绘图、综合曲线拟合(包括非线性回归)、易于理解的统计分析以及数据管理功能集于一身,帮助用…...
尚硅谷阳哥JVM
文章目录 第01章 JVM快速入门1、什么是JVM2、主流虚拟机有哪些?3、结构图3、执行引擎Execution Engine4、本地方法接口Native Interface5、Native Method Stack6、PC寄存器(程序计数器) 第02章 类加载器ClassLoader1、 类的加载过程2、类加载器的作用3、类加载器分类…...
spark的Standalone模式介绍
Apache Spark 的 Standalone 模式是其自带的集群管理模式,无需依赖外部资源管理器(如 YARN 或 Mesos),可快速部署和运行 Spark 集群。以下是对 Standalone 模式的详细介绍: 1. 核心组件 Master 节点 集群的主控制器…...
自营交易考试中,怎么用“黄昏之星”形态做出漂亮反转单?
在自营交易考试中,如何在复杂的市场波动中抓住关键的趋势反转点,常常决定了一笔交易的成败。尤其是在规则清晰、交易明确的交易考试中,具备对K线形态的敏感度,是不少EagleTrader交易员在晋级过程中总结出的实用经验。今天…...
【算法】版本号排序
对版本号数组进行排序,比如:[0.1.2.3,1.2.1.0,4.2.1.0,0.1.2.0] 核心思路 将版本号拆分为数字数组,逐个比较每个子版本段。具体步骤: 拆分版本号:将每个版本字符串按 . 分割成数字数…...
wordcount程序
### 在 IntelliJ IDEA 中编写和运行 Spark WordCount 程序 要使用 IntelliJ IDEA 编写并运行 Spark 的 WordCount 程序,需按照以下流程逐步完成环境配置、代码编写以及任务提交。 --- #### 1. **安装与配置 IntelliJ IDEA** 确保已正确安装 IntelliJ IDEA&#x…...
MySQL Explain 中 Type 与 Extra 字段详解
引言 在数据库性能调优过程中,理解执行计划(EXPLAIN)的输出信息至关重要。MySQL 的 EXPLAIN 命令能够帮助开发者分析查询的执行路径和效率,其中 Type 和 Extra 字段提供了关键的执行细节。Type 字段表示访问类型,反映…...
代码随想录算法训练营第60期第三十六天打卡
大家好!今天我们就会正式进入动态规划的章节,以前我们相继学完了回溯算法,贪心算法,今天的动态规划应该是相当重要同时也是相当难的章节,那我们废话不多说直接进入我们今天的章节。 第一部分 动态规划理论基础 那究竟…...
Python操作MySQL 连接加入缓存层完整方案
更多内容请见: python3案例和总结-专栏介绍和目录 文章目录 1、整体架构设计2、MySQL 连接方案2.1 使用连接池 (推荐)2.2 使用 SQLAlchemy (ORM方案)3、缓存层实现方案3.1 Redis 缓存实现3.2 Memcached 缓存实现4、完整集成方案4.1 带缓存的数据库访问层4.2 使用装饰器实现缓存…...
PyTorch深度神经网络(前馈、卷积神经网络)
文章目录 神经网络概述神经元模型多层感知机前馈神经网络网络拓扑结构数学表示基本传播公式符号说明整体函数视角 卷积神经网络卷积神经网络发展简史第一代(1943-1980)第二代(1985-2006)第三代(2006-至今)快…...
现代垃圾收集器
大家好,我是你们的花姐。 话说java的长期支持版本已经发展到了JDK21,大部分同学对jvm中的垃圾收集器还停留在java8之前的CMS和G1。对java11之后引入的低延迟垃圾收集器shenandoah和zgc几乎是一无所知,甚至有同学是连这两个名字也没有听过呀,…...
Android学习总结之类LiveData与ViewModel关系篇
1. ViewModel 和 LiveData 的强依赖关系 ViewModel 和 LiveData 虽非强依赖,但在 Android 架构中常紧密协作,这基于它们的设计理念和优势互补: 数据与 UI 分离:ViewModel 的主要职责是存储和管理与 UI 相关的数据,而…...
GaussDB 实例 gsql 连接方式详解
GaussDB 实例 gsql 连接方式详解 GaussDB 是华为云推出的分布式关系型数据库服务,支持多种数据库引擎(如 MySQL、PostgreSQL、SQL Server 等)。gsql 是 GaussDB 提供的命令行客户端工具,用于连接和管理数据库实例。本文将详细介绍…...
智能体制作学习笔记2——情感客服
02 案例1-情感客服_哔哩哔哩_bilibili 目录 一、AI对视频内容总结 二、选择可代替视频总结的方案 三、豆包AI插件安装 四、通义 五、情感客服智能体制作 (一)注册 (二)进入工作空间 (三)创建智能体 (…...
部署GraphRAG配置Neo4j实现知识图谱可视化【踩坑经历】
文章目录 概要部署graphrag(一)使用conda创建虚拟环境(前提已经安装好anaconda)(二)部署graphrag 部署neo4jgraphrag生成的知识图谱导入neo4j踩坑经历1.graphrag执行graphrag index --root ./ragtest命令报错2.neo4j没有Relationship types 概要 在本地部署GraphRag࿰…...
跨域的几种方案
因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名、端口有一个不同就是跨域,Ajax 请求会失败。 我们可以通过以下几种常用方法解决跨域的问题 JSONP JSONP 的原理很简单,就是利用 <script> 标签没有跨域限制…...
5 WPF中的application对象介绍
WPF Application 类提供了一系列生命周期事件,了解它们的触发顺序对于应用程序开发非常重要。以下是主要事件的触发顺序 1. 主要事件顺序 Startup - 应用程序启动时触发 这是第一个触发的事件 适合在此处初始化应用程序级资源 可以在此取消启动(通过设置e.Cancel = true) Act…...
Nexus首次亮相迪拜 TOKEN2049:以“手机 + 钱包 + 公链 + RWA”生态系统引领未来区块链基建
迪拜,2025年5月—— 全球 Web3 基础设施创新平台 Nexus,在本年度迪拜 TOKEN2049 全球峰会 上完成了其主网与全生态系统的首次国际公开亮相。此次参会不仅展示了 Nexus 的国际生态布局,更标志着其迈出了全球化战略关键一步。凭借对现实世界资产…...
C++ 套接字函数详细介绍
目录 头文件1. 套接字创建与配置2. 绑定地址与端口3. 连接建立4. 数据传输5. 套接字选项6. 地址转换7. 套接字关闭8. 其他实用函数 C 套接字函数详细介绍 套接字(Socket)是网络通信的基本端点,C中通常使用BSD套接字API进行网络编程。以下是主要的套接字相关函数及其…...
WordPress 和 GPL – 您需要了解的一切
如果您使用 WordPress,GPL 对您来说应该很重要,您也应该了解它。查看有关 WordPress 和 GPL 的最全面指南。 您可能听说过 GPL(通常被称为 WordPress 的权利法案),但很可能并不完全了解它。这是有道理的–这是一个复杂…...
机器人示教操作
机器人基础操作 **ES机器人试教操作知识** **1. 视角移动** **1.1 基础模式** - 关节轴控制:通过关节1至关节6实现单轴正反转移动 - 直线移动:通过X/Y/Z坐标轴沿指定方向直线移动 - 旋转移动:通过RX/RY/RZ坐标轴绕指定轴旋转 **1.2 步进模式…...
【python】UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xb2
报错 C:\Users\zhangbin\AppData\Local\Programs\Python\Python310\python.exe D:\XTRANS\cuda\03-graph-db\04-cmkg\pdf2zh-v1.9.9-with-assets-win64\pdf2zh\gui.py Traceback (most recent call last): File “D:\XTRANS\cuda\03-graph-db\04-cmkg\pdf2zh-v1.9.9-with-asset…...
[python] python静态方法,类方法,实例方法实现及其区别
一 静态方法 格式: 使用 staticmethmod 装饰器修饰 应用: 某个方法既不需要使用实例属性也不需要使用类属性时,就可以考虑使用静态方法 注意: 静态方法与类无关,可以被转换成函数使用,属于类本身 1.1 经典示例 创建一个与日期相关的辅助函数,这些函数不需要访问或修改类的…...
Kite AI 自动机器人部署教程
最近比较火的AI赛道,每日自动对话训练AI,赚积分 一个个用于 Kite AI 平台的自动交互机器人,支持多钱包和代理。 登记 注册链接 🌟 功能 多钱包支持(手动输入或基于文件) 代理支持(HTTP/HTTP…...
50. Pow(x, n)
50. Pow(x, n) 分治法的基本思想是将一个大问题分解成若干个相同或相似的小问题,递归地解决这些小问题,然后将这些小问题的解合并起来得到原问题的解。 class Solution:def myPow(self, x: float, n: int) -> float:# 内部定义了一个嵌套的辅助函数…...
Go 语言 sqlx 库使用:对 MySQL 增删改查
MySQL 作为目前最流行的开源关系型数据库,其 SQL 语法体系已形成行业标准,相关知识体系庞大且成熟,本文不再对 SQL 基础进行详细展开,建议尚未掌握的读者先行系统学习。本文聚焦于如何使用 Go 语言进行 MySQL 数据库操作ÿ…...
反射, 注解, 动态代理
文章目录 单元测试什么是单元测试咱们之前是如何进行单元测试的? 有啥问题 ?现在使用方法进行测试优点Junit单元测试的使用步骤删除不需要的jar包总结 反射认识反射、获取类什么是反射反射具体学什么?反射第一步:或者Class对象 获…...
继续预训练 LLM ——数据筛选的思路
GPT生成数据微调qwen-2.5多模态模型实战项目 作者:柠檬养乐多 原文地址:https://zhuanlan.zhihu.com/p/30645776656 qwen2.5-vl是阿里通义实验室推出的qwen系列最新多模态大模型,在许多指标上已经超过或接近了gpt-4o。更为方便的是࿰…...
深入解析 PostgreSQL 外部数据封装器(FDW)的 SELECT 查询执行机制
引言 PostgreSQL 中的外部数据封装器(Foreign Data Wrapper, FDW)是一种扩展,允许您像访问 PostgreSQL 数据库中的表一样,访问和操作存储在外部数据源中的数据。FDW 使 PostgreSQL 能够与多种数据存储系统(包括关系型…...
数据库系统概论|第六章:关系数据理论—课程笔记2
前言 前文我们介绍了规划化的基本概念,同时引入了关于规范化的相关定义与基本概念,低一级范式的关系模式,通过模式分解,可以转换为若干个高一级范式的关系模式的集合,这种过程就叫规范化。本文将围绕范式展开讨论&…...
package-lock.json能否直接删除?
package-lock.json能否直接删除? package-lock.json 生成工具:由 npm 自动生成。 触发条件:当运行 npm install 时,如果不存在 package-lock.json,npm 会创建它;如果已存在,npm 会根据它精确安…...
Ubuntu磁盘空间分析:du命令及常用组合
1、du命令的作用 du(Disk Usage)是 Ubuntu 系统中用于查看目录或文件磁盘使用情况的命令,主要用于分析磁盘空间占用。 2、语法 du [选项] [目录/文件路径]常用选项 2.1、-h 以 KB、MB、GB 等人性化可读格式(Human-readable&am…...
《数据库原理》部分习题解析1
《数据库原理》部分习题解析1 1. 名词解释 (1)关系(2)属性(3)域(4)元组(5)码(6)分量(7)关系模式 ࿰…...
汇川Easy系列PLC数据值改变功能块(随动增益改变判断)
PLC值改变事件 值改变触发功能块 PLC值改变事件 值改变触发功能块(SCL ST完整源代码)-CSDN博客文章浏览阅读1.1k次。本文介绍了在PLC中处理值改变事件的方法,包括值改变触发功能块的实现,详细讲解了FB接口定义、ST代码,并提供了在博途平台上的实现。此外,还分享了如何利用…...
数据清洗的艺术:如何为AI模型准备高质量数据集?
数据清洗的艺术:如何为AI模型准备高质量数据集? 引言 在人工智能和机器学习领域,我们常常听到"垃圾进,垃圾出"(Garbage in, garbage out)这句格言。无论你的模型架构多么精妙,算法多么先进,如果…...