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

007 Linux 开发工具(上)—— vim、解放sudo、gc+

🦄 个人主页: 小米里的大麦-CSDN博客
🎏 所属专栏: Linux_小米里的大麦的博客-CSDN博客
🎁 GitHub主页: 小米里的大麦的 GitHub
⚙️ 操作环境: Visual Studio 2022

在这里插入图片描述

文章目录

    • Linux 开发工具(上)
      • Linux 编辑器 —— `vim`
        • Vim 的主要模式:
        • Vim 命令模式下的一些常用操作: [史上最全 Vim 快捷键键位图(入门到进阶)](https://www.runoob.com/w3cnote/all-vim-cheatsheat.html)
        • Vim 多文件编辑与窗口管理
        • 简单的 `vim` 配置([Vim 改装](https://blog.csdn.net/wooin/article/details/1858917))
      • 解放 `sudo` 权限
      • Linux 编译器 —— `gcc `/ `g++`
        • 背景知识回顾 —— C/C++ 程序的编译流程
        • 1. 预处理 (Preprocessing)
        • 2. 编译 (Compilation)
        • 3. 汇编 (Assembly)
    • 传道解惑
      • Q1:什么是可重定位目标文件?
      • Q2:为什么需要可重定位目标文件?
      • Q3:什么时候会被最终链接?
        • 4. 链接 (Linking)
        • 为什么我们能在 Windows 或 Linux 上进行 C/C++ 开发?
        • 软件版本管理:社区版 vs 专业版
        • 关键命令与文件类型总结
        • 记忆法
      • 函数库的概念与作用
        • 函数库的分类
        • 函数库的命名规则
        • 函数库的使用
        • 函数库的作用 —— 不让我们做重复工作,站在巨人的肩膀上享受
      • Linux 中的可执行文件链接方式:动态、静态与混合链接
      • 小故事理解动静态链接
        • 1. 默认情况下,gcc 采用动态链接
        • 2. 强制使用静态链接(`-static` 选项)
        • 3. `-static` 的本质:改变库的优先级
        • 4. 混合链接(部分静态,部分动态)
        • 5. `-static` 的优缺点
        • 6. 推荐场景
      • Debug 与 Release 模式 & ELF 可执行文件格式
        • 1. Debug 模式(调试模式)
        • 2. Release 模式(发布模式)
        • 3. ELF(Executable and Linkable Format,可执行文件格式)
      • 总结
    • 共勉

Linux 开发工具(上)

Linux 编辑器 —— vim

Vim 是一个强大、多模式的文本编辑器,具有高度的可定制性和丰富的功能。打开文件:在命令行中输入 vim filename,打开指定文件。Vim 从入门到牛逼 / Vim 从入门到牛逼(备用)

打开当前目录下的文件 code.c,使用命令:vim code.c,同时 支持相对路径和绝对路径 打开:vim home/code.c

Vim 的主要模式:
  • 命令模式(Normal Mode):命令模式是 Vim 的核心模式,几乎所有操作都从这里开始,启动 Vim 后,默认处于命令模式。在此模式下,键盘输入被解释为命令而非文本输入。只能使用方向键、删除、复制、粘贴等操作用来进行文本的导航、选择、删除、替换等。(按 i 进入插入模式,按 : 进入底行模式,按 Esc 从其他模式返回到命令模式)
  • 插入模式(Insert Mode):按下 i 键进入插入模式。插入模式下可以像普通文本编辑器一样输入文本。按 Esc 键返回命令模式。
  • 底行模式(Ex Mode 或 Bottom Line Mode):底行模式是 Vim 的强大功能之一,支持复杂的文件操作和配置。按下 shift+ (也就是 :) 键进入底行模式。在底行模式下可以执行文件保存、退出、查找替换等命令。例::wq 保存并退出 Vim。按 Esc 键返回命令模式。(注意: Ctrl+C 也可以退出底行模式并返回命令模式,尽量不要使用,可能会出现未知错误)
Vim 命令模式下的一些常用操作: 史上最全 Vim 快捷键键位图(入门到进阶)

导航

  • gg: 定位光标到最开始行。
  • shift+gG: 定位光标到最结尾行。
  • n+shift+gnG: 定位光标到任意行——跳到指定行号 n
  • shift+$: 定位光标到当前行的结尾。
  • shift+^: 定位光标到当前行的开始。
  • w, b: 光标按照单词进行行内移动,分别向右或向左移动一个单词。
  • h, j, k, l: 分别移动光标左、下、上、右。

文本编辑

  • (n)yy: 复制光标所在行或指定行数的内容。
  • (n)dd: 剪切(删除)当前行或指定行数的内容。
  • (n)p: 粘贴 n (次数)行到光标所在下一行。
  • u: 撤销上一步操作。
  • ctrl+r: 撤销之前的撤销(重做撤销的操作)。

其他操作

  • shift+~: 大小写转换。
  • (n)r: 对光标字符之后的 n 个字符进行批量化替换。
  • shift+R: 进入替换模式,对内容进行整体替换 → 第四种模式。
  • (n)x: 对光标后面的 n 个字符进行删除。
  • :w 保存,:w! 强制保存,:q 退出,:q! 强制退出,:wq! 强制退出并保存

这两个命令 (shift+$shift+^) 被称为“锚点”,因为它们将光标快速固定到行的特定位置——就像锚点固定物体的位置一样。在文本编辑器中,锚点 通常指的是可以用来快速定位或固定某个位置的标记。

为什么 vim 快捷键不像现在键盘的常规操作:主要是因为早期的键盘并不像现在这样有功能键(F1-F12)、方向键或数字小键盘。Vim 的许多快捷键都是为了适应这些限制而设计的。(可以查找一下那个时代的键盘 🤪)

Vim 多文件编辑与窗口管理

在 Vim 中,你可以同时打开多个文件,并使用 分割窗口 来进行并行编辑。

打开多个文件 —— 垂直分割窗口 (vs):

  • 作用:在当前窗口 右侧 打开一个新的窗口,并加载指定的文件。
  • 用法::vs file2.c。示例:先打开 file1.c,然后在 Vim 中输入 :vs file2.c,即可在右侧创建一个窗口并打开 file2.c

窗口切换 Ctrl+w w

  • 作用:在多个窗口之间切换光标位置。
  • 操作方式:按 Ctrl+w,再按 w,光标会跳到下一个窗口。如果有多个窗口,重复 Ctrl+w w 可以在所有窗口之间循环切换。

窗口内编辑光标在哪个窗口里面,就对哪一个窗口进行操作,你可以在当前窗口进行 插入、删除、复制等编辑操作,而不会影响其他窗口。

  • 水平分割窗口::sp file2.c
  • 调整窗口大小:Ctrl+w +(增加高度)、Ctrl+w -(减少高度)。

简单的 vim 配置(Vim 改装)

Vim 的配置文件有两个主要位置,注意:一个用户配置一个 vim 文件,不会互相影响,不建议给 root 做配置,推荐用普通用户!

  1. 全局配置文件/etc/vimrc,对所有用户都生效。
  2. 用户私有配置文件:每个用户可以在其主目录下创建 .vimrc,仅对该用户生效。例如,/root/.vimrc 适用于 root 用户。

如何修改 .vimrc

  1. 切换到自己的用户目录(确保在自己的 home 目录下):cd ~
  2. 打开 .vimrc 文件(如果不存在,则创建):vim .vimrc

常用 Vim 配置

.vimrc 文件中添加以下配置:

  • 设置语法高亮:syntax on,作用: 开启 Vim 的语法高亮功能,使代码有不同颜色,提高可读性。
  • 显示行号:set nu,作用: 开启行号显示,在左侧显示每行的编号,方便定位代码行。
  • 设置缩进的空格数:set shiftwidth=4,作用: 设定每次缩进的空格数为 4。适用于代码自动缩进,提高代码可读性。

测试配置

修改 .vimrc 文件后,需要重新打开 Vim 或者在 Vim 内输入以下命令让配置生效::source ~/.vimrc 然后可以在 Vim 中测试:

  • 输入 :set nu? 检查行号是否开启。
  • 输入 :set shiftwidth? 检查缩进空格数。

这样就完成了简单的 Vim 配置! 🚀

使用插件(进阶)

Vim 支持插件扩展功能,要配置好看的 vim,原生的配置可能功能不全,可以选择安装插件来完善配置,保证用户是你要配置的用户。Vim 的插件管理工具如 Vim-Plug,一些常用的插件如 NERDTree、coc.nvim 等,以增强 Vim 的功能。

推荐使用 Vim-Plug 作为插件管理器。

  1. 安装 Vim-Plug

    curl -fLo ~/.vim/autoload/plug.vim --create-dirs \https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
    
  2. 配置插件:在 .vimrc 中添加以下内容:

    call plug#begin('~/.vim/plugged')
    Plug '插件名称'  " 例如:Plug 'preservim/nerdtree'
    call plug#end()
    
  3. 安装插件
    在 Vim 中运行 :PlugInstall 安装配置的插件。


我的 vim 配置:

安装方法:shell 中执行指令(想在哪个用户下让 vim 配置生效,就在哪个用户下执行这个指令。强烈 “不推荐” 直接在 root 下执行),需要按照提示输入 root 密码。您的 root 密码不会被上传,请放心输入。

curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh

注意:安装完成后一定要手动执行 source ~/.bashrc 或重启终端,这样配置才能生效! 说明:安装完成后,目录下会有一个名为 install.sh 的配套脚本,处于安全考虑,可以执行 mv install.sh .install.sh 进行隐藏。

默认缩进配置为 2 个字符,将 tab 键换成 4 个字符的方法:到达家目录下执行 vim .vimrc,大概在 50 行进行修改:

set tabstop=4       " 每个制表符占用 4 个空格
set softtabstop=4   " 插入制表符时插入 4 个空格
set shiftwidth=4    " 自动缩进和文本块操作时使用 4 个空格

卸载方法 在安装了 VimForCpp 的用户下执行:

bash ~/.VimForCpp/uninstall.sh

解放 sudo 权限

使用 root 账户执行命令:

vim /etc/sudoers

按下 i 键进入插入模式,找到大约第 100 行左右的位置(附近会有 root ALL=(ALL) ALL 的字眼),在其下方添加以下内容:

username    ALL=(ALL)    ALL
  • username:替换为你要授权的账户名。
  • ALL=(ALL):允许用户以任何用户身份执行命令。
  • ALL:允许执行所有命令。

Esc 键返回到默认模式,然后输入 :wq! 强制保存并退出。

验证:切换到该用户并测试 sudo 权限:

su - username
sudo ls /root

如果 sudo 配置正确,系统会提示输入密码,然后执行命令。


Linux 编译器 —— gcc / g++

背景知识回顾 —— C/C++ 程序的编译流程

C/C++ 程序从源代码到可执行文件需经历四个主要阶段:预处理 → 编译 → 汇编 → 链接。每个阶段由编译器(如 GCC、Clang 或 MSVC)逐步处理,最终生成可执行文件或库文件。

1. 预处理 (Preprocessing)

预处理是编译的第一步,主要处理源代码中的宏、注释、头文件等。预处理的输出是一个经过宏替换、去注释、头文件展开的中间代码。

主要工作:

  • 去除注释:删除代码中的注释部分。
  • 宏替换:替换代码中的宏定义(如 #define)。
  • 头文件展开:将 #include 指令包含的头文件内容插入到当前文件。
  • 条件编译:根据条件编译指令(如 #ifdef#endif)选择性地包含或排除代码。

输出:

  • 预处理后的文件通常是一个 .i 文件,它是源代码经过宏替换和头文件展开后的中间结果。

命令示例:

gcc -E temp.c -o temp.i		# 执行预处理后就停止,`-E` 选项表示只进行预处理,输出 `.i` 文件。

重要说明: 预处理后的文件仍然是 C 语言代码,因此可以说经过预处理后,程序依然是 C 语言程序。

2. 编译 (Compilation)

编译阶段的作用是将预处理后的代码转化为汇编代码。编译器会对代码进行语法分析、语义分析和优化,最终生成与平台架构相关的汇编代码。

主要工作:

  • 语法分析:检查代码是否符合语法规则。
  • 语义分析:检查变量类型、函数调用等语义是否正确。
  • 优化:对代码进行优化,使得生成的汇编代码更高效。

输出:

  • 编译后的文件是一个 .s 文件,包含了平台特定的汇编代码。

命令示例:

gcc -S temp.i -o temp.s		# 执行编译后就停止,`-S` 选项表示将预处理后的文件编译成汇编语言。
3. 汇编 (Assembly)

汇编阶段的作用是将汇编代码转换为机器可识别的二进制目标代码。汇编器会将汇编代码翻译为机器指令,生成可重定位目标文件。

主要工作:

  • 汇编:将汇编代码转换为目标代码,生成二进制文件。

输出:

  • 汇编后的文件是一个 .o(Linux)或 .obj(Windows)文件,这些文件是目标文件,包含机器指令,但尚未链接成最终的可执行文件。

命令示例:

gcc -c temp.s -o temp.o		# 执行汇编后停止,`-c` 选项表示只进行汇编,不进行链接,输出 `.o` 文件。

重要说明: 可重定位目标二进制文件,简称目标文件,.obj 文件不可以独立执行,虽然已经是二进制了,还需要经过链接才能执行!

传道解惑

在 Linux 中,可重定位目标二进制文件(Relocatable Object File)是一种 中间二进制文件,它是由编译器或汇编器生成的,但还 不能直接执行,必须经过 链接(Linking) 处理后才能成为最终的可执行文件或库文件。

Q1:什么是可重定位目标文件?

可重定位目标文件通常以 .o 结尾(Windows 上是 .obj),它包含:

  • 机器指令(Machine Instructions):程序的可执行代码,但未指定最终内存地址。
  • 符号表(Symbol Table):记录函数、变量等符号,供链接器解析。
  • 重定位信息(Relocation Information):用于在链接时调整地址。
  • 节(Section)结构:比如 .text(代码段)、.data(已初始化数据段)、.bss(未初始化数据段)等。

这些文件是 “可重定位” 的,因为它们的地址信息 尚未固定,而是由 链接器 在合并多个目标文件时决定最终的内存布局。

Q2:为什么需要可重定位目标文件?

如果编译器直接把 C/C++ 源代码编译成最终可执行程序,那么:

  • 无法将不同的模块(文件)合并,无法进行大规模项目开发。
  • 无法使用动态链接库(Shared Library),会导致程序体积庞大。
  • 无法延迟地址分配,不适用于操作系统的内存管理策略。

所以,编译器通常 生成 可重定位目标文件,再由 链接器 进行 地址调整和符号解析,最终得到可执行程序。

示例:生成可重定位目标文件

假设我们有一个简单的 C 代码 temp.c

#include <stdio.h>void hello()
{printf("Hello, World!\n");
}

第一步:编译但不链接

gcc -c temp.c -o temp.o

这样会生成 temp.o,它是一个 可重定位目标文件,里面的 hello 还没有绑定到最终的地址。

第二步:使用 readelf 查看目标文件

readelf -h temp.o

部分输出:

Type:           REL (Relocatable file)
Machine:        x86-64

可以看到 TypeREL,表示它是一个 可重定位文件

Q3:什么时候会被最终链接?

可重定位目标文件 通常不会单独使用,它最终会:

  1. 静态链接(Static Linking):被 ld(链接器)合并到最终的可执行文件中。
  2. 动态链接(Dynamic Linking):与共享库(.so 文件)进行链接,在运行时加载。

例如:

gcc temp.o -o temp
./temp

这时 temp.o 经过链接后变成可执行文件 temp,可以直接运行。

4. 链接 (Linking)

链接阶段的作用是将多个目标文件(如 .o 文件)和库文件进行链接,生成最终的可执行文件或库文件。链接器会处理符号引用、重定位等工作,确保程序能够正确运行。

主要工作:

  • 符号解析:将不同目标文件中的符号(如函数名、变量名等)进行链接,确保各部分之间的正确引用。
  • 重定位:调整代码中地址的引用,使得目标文件能够在内存中正确加载。

输出:

  • 链接后的输出通常是一个可执行文件(如 a.outprogram.exe)或动态链接库(如 .so.dll 文件)。

命令示例:

gcc source.o -o program		# 默认链接 C 标准库,这条命令将目标文件 `temp.o` 链接为可执行文件 `program`。

为什么我们能在 Windows 或 Linux 上进行 C/C++ 开发?

在 Windows 和 Linux 上进行 C/C++ 开发是因为这些操作系统提供了支持编译和执行 C/C++ 代码的工具链。具体而言,需要安装开发环境(如 GCC、Visual Studio 等)以及相关的库文件和头文件。

1. 头文件和库文件

  • 头文件:定义了语言的核心功能、标准库以及外部库的接口(如 stdio.hstdlib.h)。
  • 库文件:包含预编译的二进制代码(如 libc.amsvcrt.dll),在链接阶段与用户代码结合。

2. 开发工具

  • 编译器:如 GCC(GNU Compiler Collection)、g++,以及 Visual Studio(VS)等 IDE,提供了代码编辑、编译、调试等功能。
  • 语言支持包安装开发工具时,会自动下载头文件和库。 例如,安装 VS 时选择“C++ 开发”,会附带 C++ 标准库(如 STL)和 Windows API 库。

3. 跨平台开发

  • 条件编译:通过宏(如 #ifdef __linux__)区分不同平台的代码逻辑。
  • 平台专属库:Linux 依赖 glibc,Windows 依赖 msvcrt.dll。开发者需调用标准接口或使用跨平台库(如 Qt、Boost)。
软件版本管理:社区版 vs 专业版

1. 代码维护策略

  • 单一代码库:企业无需维护多份代码,而是通过 条件编译 控制功能模块的启用或禁用。例如:

    #ifdef PROFESSIONAL_EDITIONenableAdvancedFeatures();
    #endif
    
  • 编译参数控制:构建时通过宏定义(如 -DPROFESSIONAL_EDITION)选择版本。

2. 功能裁剪 —— 不需要维护两份代码,根据不同的编译条件,会裁剪掉社区版不需要的功能即可

  • 社区版:禁用部分高级功能(如性能分析工具、企业级加密)。
  • 专业版:包含完整功能,通过编译选项开启。

关键命令与文件类型总结
阶段命令选项输入文件输出文件文件内容
预处理-E.c.i展开后的 C 代码
编译-S.i.s汇编代码
汇编-c.s.o(Linux)目标二进制文件
链接.oa.out(默认)可执行文件
记忆法
  • ESC 键记忆法:键盘左上角的 ESC 键可以关联各个阶段的后缀:

    • .i -> 预处理(Preprocessing)
    • .s -> 汇编(Assembly)
    • .o -> 目标文件(Object file)
  • iso → 镜像文件后缀。 最终的可执行文件或库文件就是链接的结果。

    编译流程:
    .c 源文件 → 预处理 → 编译 → 汇编 → 链接 → 可执行文件(-E)     (-S)   (-c)    多文件编译例如:
    processBar.c → processBar.o ─┐├→ processBar
    processBarmain.c → processBarmain.o ─┘
    

函数库的概念与作用

在 C/C++语言编程中,函数库(Library)允许开发者复用已有的代码,而不必每次都从头开始编写。函数库通常包含一组预先编写好的函数,这些函数可以被多个程序调用。通过使用函数库,开发者可以节省时间,减少重复劳动,并提高代码的可靠性和可维护性。

函数库的分类

函数库主要分为两种类型:静态库动态库

1. 静态库(Static Library)

  • 定义:静态库在编译链接时,会将库文件的代码全部加入到可执行文件中。因此,生成的可执行文件会比较大,但在运行时不再需要库文件。
  • 后缀名:静态库的后缀名通常为 .a(例如 libmylib.a)。
  • 优点:由于库代码被直接嵌入到可执行文件中,程序运行时不需要依赖外部的库文件,因此具有较好的独立性。
  • 缺点:生成的可执行文件较大,且如果多个程序使用相同的静态库,每个程序都会包含一份库代码的副本,导致内存浪费。

2. 动态库(Dynamic Library)

  • 定义:动态库在编译链接时并不会将库文件的代码加入到可执行文件中,而是在程序运行时由操作系统的运行时链接器动态加载。这样可以节省系统的开销。
  • 后缀名:动态库的后缀名通常为 .so(例如 libmylib.so)。
  • 优点:生成的可执行文件较小,多个程序可以共享同一个动态库,节省内存和磁盘空间。此外,动态库可以在不重新编译程序的情况下更新。
  • 缺点:程序运行时需要依赖外部的库文件,如果库文件丢失或版本不兼容,程序可能无法运行。
函数库的命名规则

函数库的命名通常遵循一定的规则,以便于识别和使用。常见的命名格式为:

libname.so.XXX
  • lib 是前缀,表示这是一个库文件。
  • name 是库的名称,例如 c 表示 C 标准库。
  • .so 表示这是一个动态库(静态库通常使用 .a)。
  • XXX 是版本号,表示库的版本。

例如,libc.so.6 是 C 标准库的动态库,版本号为 6。

函数库的使用

在 C 语言中,常用的函数库如 printf 函数的实现并没有直接包含在源代码中,也没有在头文件 stdio.h 中定义。那么,这些函数是如何被调用的呢?

1. 头文件的作用:头文件(如 stdio.h)中只包含了函数的声明(即函数原型),告诉编译器这些函数的存在及其参数和返回值的类型。头文件并不包含函数的实现。

2. 库文件的作用:函数的实现通常位于库文件中。例如,printf 函数的实现位于 C 标准库的动态库 libc.so.6 中。编译器在链接阶段会将这些库文件与代码结合起来,生成最终的可执行文件。

3. 链接过程

  • 静态链接:在编译时,静态库的代码会被直接嵌入到可执行文件中。生成的可执行文件不依赖外部的库文件。
  • 动态链接:在编译时,动态库的代码不会被嵌入到可执行文件中。程序运行时,动态链接器会根据预定义的路径规则去查找这些库文件。
函数库的作用 —— 不让我们做重复工作,站在巨人的肩膀上享受
  • 代码复用:避免重复造轮子,开发者可以直接使用封装好的函数,而不用自己实现复杂的功能。
  • 隐藏源码:共享库只提供 .so 文件,而不公开 .c 源文件,保护代码的知识产权。
  • 提高程序效率:通过动态链接的方式,多个程序可以 共享同一份库文件,减少内存占用,提高运行效率。

Linux 中的可执行文件链接方式:动态、静态与混合链接

在 Linux 中,gcc 编译形成可执行程序时,默认采用动态链接,即程序运行时依赖 .so(共享库),这样可以减少可执行文件的大小,并允许多个程序共享相同的库文件。然而,我们可以通过 静态链接混合链接 的方式来改变默认的链接行为。

小故事理解动静态链接

想象一下,你正在设计一款可以快速适应不同地形的汽车。为了实现这一目标,你决定使用一些通用的动态链接库,比如“越野轮子”、“城市轮胎”和“雪地链”。这些组件可以在不同的车型之间共享,并且可以根据需要在车辆启动时或行驶过程中即时替换。如果一个顾客今天想要一辆适合城市驾驶的汽车,你可以安装“城市轮胎”;如果明天他想去越野冒险,只需更换为“越野轮子”。这种灵活性就像动态链接(库),程序运行时按需加载,多个程序共享,节省内存,灵活高效。

另一方面,有些汽车组件一旦安装就不能轻易更改了,例如车身结构或者发动机。这些是根据特定需求量身定做的。当你选择了一种类型的发动机后,它就永久性地成为汽车的一部分,无法在不拆卸整个汽车的情况下进行更换。静态链接库就像发动机,在编译时整合进程序,成为其固定组成部分,提供稳定功能,但程序体积较大,独立运行。

1. 默认情况下,gcc 采用动态链接

当我们编译 C 语言程序:

gcc hello.c -o hello

默认情况下,gcc 优先链接动态库.so),并在执行时加载库文件。例如,标准 C 库 libc.so.6 是动态链接的:

ldd hello

示例输出:

linux-vdso.so.1 =>  (0x00007fffca9fe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2a4c3c9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2a4c788000)

这表示 hello 依赖 libc.so.6,而不是 libc.a(静态库)。

2. 强制使用静态链接(-static 选项)

如果想让程序采用 纯静态链接,可以使用 -static 选项:

gcc hello.c -o hello -static

这时,编译器会 优先查找并链接静态库(.a,把所有库代码嵌入可执行文件中,使其不再依赖外部 .so 文件。检查:

ldd hello

如果是纯静态链接,输出会是:

not a dynamic executable

这表明 hello 不依赖任何动态库

3. -static 的本质:改变库的优先级

使用 -static 选项时,必须保证所有依赖库的静态版本(.a)都存在,否则,编译会失败。如果没有静态库,但强制使用 -static 会报错!如果系统只有静态库,没有动态库,即使没有 -staticgcc 仍然会成功编译,并采用静态链接。因为它找不到 .so 文件,只能用 .a

  • 默认情况下gcc 优先选择动态库(.so
  • 加上 -staticgcc 强制使用静态库(.a,如果找不到静态库,则会报错。
  • 并且 -static 是“一次性”的,即:
    • 所有 需要的库都必须静态链接。
    • 不能部分使用动态库,部分使用静态库

如果 -static 选项下某个库没有 .a 文件,编译就会失败。

4. 混合链接(部分静态,部分动态)

虽然 -static 会让所有库都静态链接,但我们可以通过手动指定库的链接方式,实现 混合链接(部分库静态,部分库动态)。

让特定库使用静态链接:使用 -Wl,-Bstatic 指定部分库静态链接:

gcc hello.c -o hello -Wl,-Bstatic -lcustomlib -Wl,-Bdynamic -lc
  • -Wl,-Bstatic-lcustomlib 采用静态库 libcustomlib.a
  • -Wl,-Bdynamic-lc 采用动态库 libc.so(恢复默认动态链接)。
  • 这样就实现了 混合链接(部分库静态,部分库动态)。
5. -static 的优缺点
方式优点缺点
动态链接(默认)- 可执行文件小,多个程序共享库,节省磁盘、内存、网络等空间 - 库可以独立更新,不需重新编译程序- 依赖外部 .so 文件,库缺失时程序无法运行
静态链接(-static)- 程序可以独立运行,无需依赖库文件 - 适用于嵌入式系统或无共享库的环境- 可执行文件大(是动态的几十上百倍!),占用更多磁盘、内存、网络空间 - 无法通过库更新修复漏洞,需要重新编译
6. 推荐场景
场景建议链接方式
普通 Linux 应用默认动态链接(节省空间,便于更新)
需要独立运行的程序静态链接(-static,避免外部依赖
服务器软件混合链接,关键库静态,其余动态
嵌入式系统静态链接,减少依赖

Debug 与 Release 模式 & ELF 可执行文件格式

1. Debug 模式(调试模式)
  • 包含调试信息(如变量名、函数符号表)。
  • 没有优化,代码尽量保持源代码的执行逻辑,方便调试。
  • 可追踪调试,可以用 gdb(GNU Debugger)进行断点、变量查看等操作。

编译方式:

gcc -g hello.c -o hello_debug
  • -g 选项:生成调试信息,方便 gdb 进行调试。
  • hello_debug:可执行文件,但体积较大,因为包含了额外的调试信息。

调试方式:

gdb ./hello_debug		# 可以设置断点、查看变量值等。
2. Release 模式(发布模式)
  • 优化代码,提高执行效率
  • 去除调试信息,减小可执行文件大小
  • 适用于正式发布的程序,但不方便调试。

编译方式:

gcc -O2 hello.c -o hello_release
  • -O2(优化等级 2):让编译器优化代码,提高执行速度(-O3 可进一步优化)。
  • 没有 -g,不生成调试信息
3. ELF(Executable and Linkable Format,可执行文件格式)

在 Linux 下,可执行程序形成的时候,不是无顺的二进制构成,可执行程序有自己的二进制格式 —— ELF 格式。

  • 程序头部(Program Header):描述如何加载程序。
  • 代码段(.text):存放程序的可执行代码。
  • 数据段(.data、.bss):存放全局变量、静态变量等。
  • 符号表(仅 Debug 模式下存在):包含函数、变量等信息,方便调试器使用。

查看 ELF 结构:

readelf -h hello_debug   # 查看 ELF 头部信息
objdump -d hello_debug   # 反汇编可执行文件

总结

GCC/G++ 在 Linux 下的常用编译选项

选项作用示例
-o <文件名>指定输出的可执行文件名(gcc -o 输出文件 源文件gcc 源文件 -o 输出文件 均可,更推荐后者!)gcc hello.c -o hello
-c仅编译,不进行链接,生成 .o 目标文件gcc -c hello.c -o hello.o
-g生成调试信息,便于 gdb 调试gcc -g hello.c -o hello_debug
-O0不优化,适用于 Debuggcc -O0 hello.c -o hello
-O1基本优化,适用于一般调试gcc -O1 hello.c -o hello
-O2标准优化,提高性能,适用于 Releasegcc -O2 hello.c -o hello
-O3高级优化,可能影响可读性和调试gcc -O3 hello.c -o hello
-Wall启用所有常见警告gcc -Wall hello.c -o hello
-Wextra启用额外的警告信息gcc -Wall -Wextra hello.c -o hello
-Werror把所有警告当作错误gcc -Werror hello.c -o hello
-static进行 静态链接,不依赖 .sogcc -static hello.c -o hello
-shared生成 共享库(动态库) .so 文件gcc -shared -fPIC hello.c -o libhello.so
-fPIC生成位置无关代码(用于动态库)gcc -fPIC -c hello.c -o hello.o
-L<路径>指定库文件搜索路径gcc hello.c -L/usr/local/lib -lhello -o hello
-I<路径>指定头文件搜索路径gcc hello.c -I/usr/local/include -o hello
-l<库名>链接指定的库(默认搜索 /lib/usr/libgcc hello.c -lm -o hello(链接 libm.so 数学库)
-pthread支持多线程编译gcc hello.c -pthread -o hello
-std=<标准>指定 C 或 C++ 标准gcc -std=c99 hello.c -o hello
-D<宏定义>定义宏,等效于 #definegcc -DDEBUG hello.c -o hello
-E仅进行 预处理,输出 .i 文件gcc -E hello.c -o hello.i
-S仅进行 编译,输出汇编代码 .s 文件gcc -S hello.c -o hello.s
-v显示详细的编译过程gcc -v hello.c -o hello
--version显示 gcc/g++ 版本gcc --version

G++ 额外的选项

选项作用示例
-fno-rtti禁用运行时类型识别(RTTI)g++ -fno-rtti hello.cpp -o hello
-fno-exceptions禁用异常处理(try/catchg++ -fno-exceptions hello.cpp -o hello
-std=c++11使用 C++11 标准g++ -std=c++11 hello.cpp -o hello
-std=c++17使用 C++17 标准g++ -std=c++17 hello.cpp -o hello
-std=c++20使用 C++20 标准g++ -std=c++20 hello.cpp -o hello

gccg++ 的关系

  • g++ 可以使用 gcc 的全部选项,因为 g++ 本质上是 gcc 的一个前端,专门用于编译 C++ 代码。

  • gcc 既可以编译 C 也可以编译 C++,但默认 不会自动链接 C++ 标准库

  • g++ 默认 会自动链接 C++ 标准库(如 libstdc++),并开启 C++ 语法支持。

共勉

在这里插入图片描述
在这里插入图片描述

相关文章:

007 Linux 开发工具(上)—— vim、解放sudo、gc+

&#x1f984; 个人主页: 小米里的大麦-CSDN博客 &#x1f38f; 所属专栏: Linux_小米里的大麦的博客-CSDN博客 &#x1f381; GitHub主页: 小米里的大麦的 GitHub ⚙️ 操作环境: Visual Studio 2022 文章目录 Linux 开发工具&#xff08;上&#xff09;Linux 编辑器 —— vim…...

React学习路线图-Gemini版

前端开发学习路线图 (针对编程新手&#xff0c;主攻 React 框架) 总原则&#xff1a;先打好地基&#xff0c;再盖楼。 无论学习哪个框架&#xff0c;扎实的 HTML、CSS 和 JavaScript 基础是成功的关键。React 是基于 JavaScript 构建的&#xff0c;所以深入理解 JS 至关重要。…...

注意力(Attention)机制详解(附代码)

Attention机制是深度学习中的一种技术&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;和计算机视觉领域中得到了广泛的应用。它的核心思想是模仿人类的注意力机制&#xff0c;即人类在处理信息时会集中注意力在某些关键部分上&#xff0c;而忽略其他不那么重要的…...

国内外Agent产品进展汇总

MCP&#xff08;Model Context Protocol&#xff09;是一个开放标准协议&#xff0c;旨在标准化应用程序向大型语言模型提供上下文信息的方式。通过集成MCP扩展&#xff0c;Agent可以访问和利用各种外部工具和服务&#xff0c;丰富了Agent的功能范围&#xff0c;使其能够执行更…...

AI Workflow

AI Workflow&#xff08;人工智能工作流&#xff09;指的是在构建、部署和管理AI模型与应用时所涉及的一系列步骤和流程。它将数据处理、模型训练、评估、部署及监控等环节有机结合起来&#xff0c;以实现高效、可重复的AI解决方案开发过程。以下是对AI Workflow核心组成部分及…...

MySQL OCP 认证限时免费活动​ 7 月 31 日 前截止!!!

为庆祝 MySQL 数据库发布 30 周年&#xff0c;Oracle 官方推出限时福利&#xff1a;2025 年 4 月 20 日至 7 月 31 日期间&#xff0c;所有人均可免费报考 MySQL OCP&#xff08;Oracle Certified Professional&#xff09;认证考试。该认证验证持证者在 MySQL 数据库管理、优化…...

【无标题】MPC软件

MPC软件是一款先进的多变量预测控制解决方案 专为复杂工业过程优化设计 **核心功能** 实时动态建模 多变量协调控制 滚动时域优化 自适应调整策略 干扰抑制 鲁棒性强 适用于时变系统 **技术优势** 基于模型预测算法 提前计算最优控制序列 处理输入输出约束 保障系…...

【EasyPan】loadDataList方法及checkRootFilePid方法解析

【EasyPan】项目常见问题解答&#xff08;自用&持续更新中…&#xff09;汇总版 一、loadDataList方法概览 /*** 文件列表加载接口* param session HTTP会话对象* param shareId 必须参数&#xff0c;分享ID&#xff08;使用VerifyParam进行非空校验&#xff09;* param …...

Java程序题案例分析

目录 一、基础语法 1. 类与对象 2. 接口与抽象类 二、面向对象语法 1. 继承与多态 2. 四种访问修饰符 三、设计模式相关语法 一、策略模式&#xff08;接口回调实现&#xff09; 1. 完整实现与解析 二、工厂模式&#xff08;静态工厂方法实现&#xff09; 1. 完整实…...

【Lanqiao】数位翻转

题目&#xff1a; 思路&#xff1a; 写蓝桥不能不写dp&#xff0c;就像.... 题目数据给的不大&#xff0c;所以我们可以考虑一种 n*m 的做法&#xff0c;那么对于这种题目可以想到的是用dp来写&#xff0c;但是如何构造转移方程与状态是个难事 由于这题对于任意一个数我们有两…...

基于QT(C++)实现(图形界面)校园导览系统

校园导览系统 一、任务描述 大学校园充满着忙忙碌碌的学生和老师们&#xff0c;但是有时候用户宝贵的时间会被复杂的道路和愈来愈多的建筑物的阻碍而浪费&#xff0c;为了不让同学们在自己的目的地的寻路过程中花费更多的时间&#xff0c;我们着手开发这样一款校园导览系统。…...

【C/C++】虚函数

&#x1f4d8; C 虚函数详解&#xff08;Virtual Function&#xff09; &#x1f4cc; 什么是虚函数&#xff1f; 虚函数&#xff08;Virtual Function&#xff09; 是 C 中实现运行时多态&#xff08;Runtime Polymorphism&#xff09; 的核心机制。 它允许派生类 重写&…...

no main manifest attribute, in xxx.jar

1、问题&#xff1a; Spring Boot项目在idea中可以正常运行&#xff0c;但是运行Spring Boot生成的jar包&#xff0c;报错&#xff1a; 1、no main manifest attribute, in xxx.jar 2、xxx.jar中没有主清单属性 2、解决办法&#xff1a; 删除pom.xml中<configuration&g…...

使用 AI 如何高效解析视频内容?生成思维导图或分时段概括总结

一、前言 AI 发展的如此迅速&#xff0c;有人想通过 AI 提效对视频的解析&#xff0c;怎么做呢&#xff1f; 豆包里面有 AI 视频总结的功能&#xff0c;可以解析bilibili网站上部分视频&#xff0c;如下图所示&#xff1a; 但有的视频解析时提示&#xff1a; 所以呢&#x…...

比较入站和出站防火墙规则

组织需要仔细配置防火墙规则&#xff0c;监控网络的传入和传出流量&#xff0c;从而最大限度降低遭受攻击的风险。在有效管理入站和出站防火墙规则前&#xff0c;了解入站与出站流量的区别至关重要。 一、什么是入站流量&#xff1f; 入站流量指的是并非源自网络内部&#xf…...

开放式耳机什么品牌的好用?性价比高的开放式耳机品牌推荐一下

这几年蓝牙耳机发展得很快&#xff0c;从最早的入耳式&#xff0c;到现在流行的开放式&#xff0c;选择越来越多。我自己是比较偏向佩戴舒适的类型&#xff0c;用过开放式之后就回不去了。它不堵耳、不压迫&#xff0c;戴着轻松不累&#xff0c;对我这种耳朵容易不适的人来说太…...

WPF之高级绑定技术

文章目录 引言多重绑定&#xff08;MultiBinding&#xff09;基本概念实现自定义IMultiValueConverterMultiBinding在XAML中的应用示例使用StringFormat简化MultiBinding 优先级绑定&#xff08;PriorityBinding&#xff09;基本概念PriorityBinding示例实现PriorityBinding的后…...

k8s高可用集群,自动化更新证书脚本

#!/bin/bash # 切换到证书目录 cd /etc/kubernetes/pki || exit # 备份原有证书&#xff08;重要&#xff01;&#xff09; sudo cp -r apiserver.crt apiserver.key \ apiserver-etcd-client.crt apiserver-etcd-client.key \ apiserver-kubelet-client…...

【Python 函数】

Python 中的函数&#xff08;Function&#xff09;是可重复使用的代码块&#xff0c;用于封装特定功能并提高代码复用性。以下是函数的核心知识点&#xff1a; 一、基础语法 1. 定义函数 def greet(name):"""打印问候语""" # 文档字符串&…...

Filecoin矿工资金管理指南:使用lotus-shed actor withdraw工具

Filecoin矿工资金管理指南&#xff1a;使用lotus-shed actor withdraw工具 引言lotus-shed actor withdraw命令概述命令语法参数选项详解常见使用场景1. 提取全部可用余额2. 提取指定数量的FIL3. 通过受益人地址发送交易 最佳实践资金安全管理操作流程优化 常见问题与解决方案提…...

AI辅助DevOps与自动化测试:重构软件工程效率边界

随着AI技术渗透至软件开发生命周期&#xff0c;DevOps与自动化测试领域正经历颠覆性变革。本文系统性解析AI在需求分析、测试用例生成、部署决策、异常检测等环节的技术实现路径&#xff0c;结合微软Azure DevOps、Tesla自动驾驶测试等典型场景&#xff0c;探讨AI如何突破传统效…...

css内容省略——text-overflow: ellipsis

title: css内容省略 date: 2025-05-07 19:41:17 tags: css text-overflow: ellipsis text-overflow: ellipsis用于在文本溢出容器时显示省略号(…) 1.单行省略 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"&g…...

nginx性能优化与深度监控

一、性能调优方向 1. 系统层面优化 内核参数调整 TCP队列与连接管理&#xff1a; net.core.somaxconn&#xff08;最大连接队列长度&#xff0c;建议设为65535&#xff09;net.ipv4.tcp_max_syn_backlog&#xff08;SYN队列长度&#xff0c;建议65535&#xff09;net.ipv4.tc…...

leetcode 70.爬楼梯(c++详细最全解法+补充知识)

目录 题目 解答过程 补充哈希表知识 哈希表基本特性 常用成员函数 基本用法 实现代码 1.递归 2.循环遍历 3.哈希表 题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#…...

护照阅读器简介

护照阅读器简介 护照阅读器&#xff08;Passport Reader&#xff09;是一种专用设备&#xff0c;用于快速、准确地读取护照、身份证、签证等旅行证件的机读区&#xff08;MRZ&#xff09;和芯片&#xff08;ePassport&#xff09;信息&#xff0c;广泛应用于出入境管理、机场安…...

切片和边缘计算技术分析报告

切片和边缘计算技术分析报告 一、引言 随着 5G 通信技术的快速发展&#xff0c;网络切片和边缘计算技术逐渐成为通信领域的热点研究方向。网络切片技术通过将物理网络划分为多个逻辑上的虚拟网络&#xff0c;以满足不同业务场景对网络性能的差异化需求。边缘计算则将计算、存…...

vue3笔记(自存)

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…...

多线服务器具有什么优势

在当今数字化飞速发展的时代&#xff0c;多线服务器宛如一位低调的幕后英雄&#xff0c;默默为我们的网络世界提供着强大的支持。那么&#xff0c;多线服务器到底具有哪些令人瞩目的优势呢 首先&#xff0c;多线服务器的最大优势之一就是网络访问的高速与稳定。想象一下&#x…...

Azure OpenAI 聊天功能全解析:Java 开发者指南

Azure OpenAI 聊天功能全解析&#xff1a;Java 开发者指南 前言 在当今人工智能飞速发展的时代&#xff0c;AI 驱动的文本生成技术正深刻改变着众多应用场景。Azure OpenAI 作为这一领域的重要参与者&#xff0c;由 ChatGPT 提供支持&#xff0c;不仅具备传统 OpenAI 的功能&…...

【情感关系】健全自我

一些看到后深有感触的文字 请大家无论如何也不要相信这种&#xff1a;“童年/原生家庭经历决定人生走向”的论调。 过去可以影响我们但是无法主宰我们&#xff0c;人是有主观能动意识的&#xff0c;认识自己的问题就是改变人生轨迹的第一步。 后来我们会发现&#xff0c;对于…...

SLAM:单应矩阵,本质矩阵,基本矩阵详解和对应的c++实现

单应矩阵(Homography Matrix) 单应矩阵(Homography Matrix)是计算机视觉中描述同一平面在不同视角下投影变换的核心工具,广泛应用于图像校正、拼接、虚拟广告牌替换等场景。以下从原理、求解方法和C++实现三方面展开详解: 一、单应矩阵的数学原理 定义与作用 单应矩阵是…...

数据报(Datagram)与虚电路(Virtual Circuit)的区别

数据报&#xff08;Datagram&#xff09;与虚电路&#xff08;Virtual Circuit&#xff09;的区别 数据报和虚电路是计算机网络中两种不同的通信方式&#xff0c;主要区别体现在 连接方式、路由选择、可靠性、延迟和适用场景 等方面。以下是它们的详细对比&#xff1a; 1. 基本…...

工业现场ModbusTCP转EtherNETIP网关引领生物现场领新浪潮

生物质发生器是一种能够产生、培养生物的设备。客户现场需要将生物发生器连接到罗克韦尔系统&#xff0c;但是二者协议无法直接通讯&#xff0c;需要通过ModbusTCP转Ethernet/IP网关将两者进行通讯连接&#xff0c;生物质发生器以其独特的工作原理和优势&#xff0c;使得生物的…...

DeepSeek的100个应用场景

在春节前夕&#xff0c;浙江杭州的AI企业DeepSeek推出了其开源模型DeepSeek-R1&#xff0c;以仅相当于Open AI最新模型1/30的训练成本&#xff0c;在数学、编程等关键领域展现出媲美GPT-o1的出色性能。发布仅数日&#xff0c;DeepSeek-R1便迅速攀升至中美两国苹果应用商店免费榜…...

【Linux 系统调试】Linux 调试工具strip使用方法

‌ 目录 ‌ 一. strip 工具的定义与核心作用‌ ‌1. strip 是什么&#xff1f;‌ 2. strip 工具调试符号的作用‌ 3. strip 工具调试符号的重要性‌ 二. 如何确认文件是否被 strip 处理&#xff1f;‌ 1. 通过 file 命令检查文件状态 2. strip 的典型用法‌ ‌基础命…...

Solana批量转账教程:提高代币持有地址和生态用户空投代币

前言 Solana区块链因其高吞吐量和低交易费用成为批量操作&#xff08;如空投&#xff09;的理想选择。本教程将介绍几种在Solana上进行批量转账的方法&#xff0c;帮助您高效地向多个地址空投代币。 solana 账户模型 在Solana中有三类账户&#xff1a; 数据账户&#xff0c;…...

leetcode hot100 技巧

如有缺漏谬误&#xff0c;还请批评指正。 1.只出现一次的数字 利用异或运算相同得0的特点。所有出现过两次的数字都会在异或运算累加过程中被抵消。、 class Solution { public:int singleNumber(vector<int>& nums) {int res0;for(int i0;i<nums.size();i) re…...

搭建spark伪分布集群

1.先查看虚拟机的默认名称&#xff0c;将其修改为vm01 2.更改了主机名&#xff0c;还需要修改/etc/hosts文件&#xff0c;在这个文件设定了IP地址与主机名的对应关系&#xff0c;类似DNS域名服务器的功能 3.修改spark相关配置文件&#xff0c;包括spark-env.sh和slave两个文件 …...

vue3自定义audio音频播放【进度条,快进,后退,音量加减,播放速度】

本文将介绍如何使用Vue3构建一个功能完备的自定义音频播放器&#xff0c;包含进度条控制、快进/后退、音量调节和播放速度控制等功能。相比使用浏览器默认的audio控件&#xff0c;自定义播放器可以提供更一致的用户体验和更灵活的设计空间&#xff0c;复制粘贴即可使用&#xf…...

学习基本开锁知识

本文主要内容 目前市面上锁的种类有哪些 机械锁 钥匙开锁 &#xff1a;这是最常见的传统开锁方式&#xff0c;通过插入匹配的钥匙转动来开锁&#xff0c;如常见的家用门锁、汽车门锁等&#xff0c;钥匙形状和齿纹各异&#xff0c;有单排齿的一字锁、双排齿的双面锁&#xff0c;…...

泛微ECOLOGY9 流程表单中添加按钮的方法

使用场景介绍 有时需要在流程表单中添加一个按钮来实现弹窗、打开指定的页面等需求。 实现方式一:通过ID 在流程表单中想要生成按钮的地方指定一个ID,然后再到ecode中创建按钮及方法。 具体步骤如下: 一、表单中指定ID为 exceldc 二、在ecode中实现按钮及功能。 1.建立…...

小刚说C语言刷题—1331 做彩纸花边

1.题目描述 李晓芳用一条长为 n 米的彩纸制作花边&#xff0c;每朵花李晓芳用一条长为 n 米的彩纸制作花边&#xff0c;每朵花的宽度为 x 厘米&#xff0c;花与花之间的间隔为 y 厘米。请问 n 米的彩纸最多能做多少朵花的花边。 如&#xff0c;图中的案例花的宽度为 4.5cm &a…...

【Python】读取excel文件的时候,遇到“Excel file format cannot be determined”的问题

使用os.path 读取路径下的文件&#xff0c;并拼接文件名&#xff0c;可能会遇到这个问题&#xff1a; ValueError: Excel file format cannot be determined, you must specify an engine manually. 因为我用的是相对路径的拼接的方法&#xff0c;读取出来会有这样的问题&#…...

天气预报、天气查询API接口文档 | 实时天气 | 七日天气 | 15日天气查询

天气预报、天气查询API接口文档 | 实时天气 | 七日天气 | 15日天气查询 这篇文章详细介绍了一种天气查询服务&#xff0c;提供了实时天气(1天)、7天预报和15天预报三个RESTful接口&#xff0c;支持通过地区名称、编码、IP或经纬度等多种方式查询&#xff0c;返回数据包含温度、…...

Linux中的线程安全与线程同步详解

在Linux系统中&#xff0c;线程安全性是指在多个线程同时访问共享资源时&#xff0c;能够确保这些共享资源不被破坏或者产生数据错误。线程同步是一种机制&#xff0c;用于保证多个线程之间的操作次序和协调&#xff0c;以避免竞态条件、死锁等问题。 以下是线程安全和线程同步…...

qwen2.5vl

多模态大模型通用架构&#xff1a; 在通用的MM-LLM&#xff08;Multi-Modality LLM&#xff09;框架里&#xff0c;共有五个模块&#xff0c;整体以LLM为核心主干&#xff0c;分别在前后有一个输入、输出的投影模块&#xff08;Projector&#xff09;&#xff0c;投影模块主要…...

国产Word处理控件Spire.Doc教程:在Java中为Word文本和段落设置边框

在 Word 文档中添加边框是一种突显重点信息的有效方式&#xff0c;尤其适用于包含大量文本的内容场景。相比普通格式&#xff0c;给字符或段落添加边框不仅能强化视觉层次&#xff0c;还能提升文档的专业感与可读性。E-iceblue旗下Spire系列产品是国产文档处理领域的优秀产品&a…...

【CUDA C实战演练】CUDA介绍、安装、C代码示例

文章目录 0. 前言1. 并行计算与异构计算1.1 并行计算&#xff08;Parallel Computing&#xff09;1.2 异构计算&#xff08;Heterogeneous Computing&#xff09; 2. CUDA 的核心概念2.1 主机&#xff08;Host&#xff09;与设备&#xff08;Device&#xff09;2.2 线程层次结构…...

滑动窗口——无重复字符最长的字串

题目&#xff1a; 子字符串&#xff0c;我们也可以看成子数组。 题意不难理解&#xff0c;这个题我们暴力枚举的思路是把每一个字符遍历存到hash桶中&#xff0c;如果放两次就进行结果更新。 但这个题我们有更优化的方法&#xff0c;利用数组代替hash&#xff08;重点不在这&…...

QT中connect高级链接——指针、lambda、宏

1、connect使用指针 connect(button,&QPushButton::released,this,&MainWidget::mySlot); //【抬起】按钮button时&#xff0c;修改按钮b2的标题 2、使用lambda表达式 引入lambda表达式&#xff0c;类似内联函数&#xff0c;可以用于不会被重用的短代码片段&#x…...