Windows核心编程 静态库与动态库
资源文件 .rc 文件 会被 rc.exe 变成 .res 文件(二进制文件) 在链接时链接进入 .exe 文件
一、如何保护源码
程序编译链接过程

不想让别人拿到源代码,但是想让其使用功能,根据上图观察,把自己生成的obj给对方,对方拿到obj后,链接到自己的程序中。
新建一个控制台项目进行测试,目录结构

Math.h

Math.cpp

test.cpp

编译后,会生成一个 Math.obj的文件
再新建一个工程使用Math.obj
首先,包含头文件,其次需要导入 .obj文件
方式一:直接托进解决方案里;

方式二:项目-属性-链接器-输入-附加依赖项-箭头-编辑-添加obj文件(一行一个obj文件)

项目目录结构

Math.h


如何兼容C?
test.c

链接时报错

原因:
C语言的名称粉碎是:_Sub,_Add;
C++的名称粉碎是: ?Sub@@YAHHH@Z,?Add@@YAHHH@Z
编译器拿着“?Sub@@YAHHH@Z”,在obj中匹配C的_Sub,当然匹配不上解决办法:告诉编译器,名称粉碎的时候,按照C的名称粉碎规则进行粉碎。
C++ 项目使用时,函数声明加上extern "C"后,C++支持extern "C"语法,能够直接使用
C项目使用时,由于函数声明上extern "C",但是C不支持该语法,不认识,所以编译不通过解决办法:头文件被C 包含的时候前面不加extern "C" int Add(int n1, int n2);
头文件被C++ 包含的时候,声明前面加上extern "C" ,说明用C风格名称粉碎去找实现extern "C"条件编译宏:这样使用的时候就可以不管是C包含还是Cpp包含了
//要想C 和C++ 都能所用该obj,声明的前面必须加上extern "C",生成的obj文件名称粉碎是C风格的。C++可以使用,C也可以使用
//C++ 项目使用时,函数声明加上extern "C"后,C++支持extern "C"语法,能够直接使用
//C 项目使用时,由于函数声明上extern "C",但是C不支持该语法,不认识,所以编译不通过。//解决办法:头文件被C 包含的时候前面不加extern "C" int Add(int n1, int n2);
// 头文件被C++ 包含的时候,声明前面加上extern "C" ,说明用C风格名称粉碎去找实现extern "C" int Add(int n1, int n2);//条件编译宏:这样使用的时候就可以不管是C包含还是Cpp包含了
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplusint Add(int n1, int n2);#ifdef __cplusplus
}
#endif // __cplusplus
上述的obj的方法中,当有很多obj时候,需要拷贝很多的obj,很不方便,考虑将这些obj合并成一个大的“obj”,这时就引出了静态库的概念。
补充:
#pragma once 是一种预处理指令,用于确保头文件只被编译一次。当一个头文件被多次包含在不同的源文件中时,使用 #pragma once 可以防止重复包含,从而避免编译错误和重复定义的问题。
#pragma once 的作用类似于传统的头文件保护宏(header guard),但更加简洁和方便。传统的头文件保护宏需要在头文件开头和结尾分别使用条件编译语句,如 #ifndef HEADER_NAME_H、#define HEADER_NAME_H 和 #endif,以确保头文件只被编译一次。而 #pragma once 只需要在头文件的开头使用一次,即可达到相同的效果。
使用 #pragma once 的好处是可以提高编译速度,因为编译器可以直接根据指令判断是否需要重新编译头文件。而传统的头文件保护宏需要进行条件判断,会增加编译时间和额外的预处理工作。
二、静态库 动态库 概述
函数和数据被编译进一个二进制文件(通常扩展名为.lib)。在使用静态库的情况下,在编译可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.exe文件)。
本质:把所有的obj文件全部打包到一个.lib文件内。
缺点:
- 维护困难:如果.lib更新,使用的工程如需更新,则必须重新编译。
- 磁盘冗余:如果很多工程使用,就要拷贝很多份.lib文件,这些lib都是一样的
- 无法很好的同时兼容C和C++
- 其他语言无法使用
动态链接库(DLL) 通常不能直接运行,也不能接收信息,只有在其他模块调用动态链接库中的函数时,才能发挥作用。通常我们把完成某种功能的函数放在一个动态链接库中,提供给其他程序调用。DLL就是整个windows操作系统的基础。动态链接库不能直接运行,也不能接收消息。他们是一些独立的文件。
Windows API中所有的函数都包含在DLL中,其中有3个重要的DLL:
- Kernel32.dll:包含用于管理内存、进程和线程的函数、例如CreateThread函数。
- User32.dll:它包含用于执行用户界面任务(如窗口的创建和消息的传送)的函数。例如CreateWindow函数。
- GDI32.dll:它包含用于画图和显示文本的函数。
使用动态链接库的好处:
- 可以采用多种编程语言来编写。
- 增强产品的功能(扩展插件)
- 提供二次开发的平台(扩展插件)
- 简化项目管理(一个团队负责自己团队的dll)
- 可以节省磁盘空间和内存
- 有助于资源的共享
- 有助于实现应用程序的本地化。
三、静态链接库创建与使用
VS2019中直接找到静态链接库,一路确认即可
不适用预编译头即可


项目目录:

pch.h framework.h 文件是作用是减少重复文件编译,提升性能有关。不用管
如果想建立一个自己的静态链接库,直接添加 .h .cpp文件即可,编译后就可以得到 .lib 文件
使用静态库和使用 .obj 类似
1. 添加头文件,使用者才能知道传的什么参数以及其他
2. 拷贝lib文件和.h头文件到VS工程根目录
3. 添加lib文件到工程的方式(用法):
a. 直接拖入项目中
b. 依赖项添加.lib文件
c. 代码内添加.lib文件 # pragma comment(lib,lib路径)

如何把两个 obj 合成为 lib

静态库中还可以放 全局变量,类(通过源文件右击添加-类)


四、动态链接库创建
新建>>类向导>>项目类型>>.dll动态链接库。

动态链接库中有导出函数和非导出函数:
- 导出函数:DLL提供给其他应用程序调用的函数
- 非导出函数:给DLL内的函数调用的函数,中间函数等。
如果想导出函数给外面的工程使用,需要指定函数,告诉编译器哪个函数需要导出
从DLL中导出函数:
为了让DLL导出一些函数,需要在每一个将要被导出的函数前面添加标识符__declspec(dllexport)
编译:生成DLL文件和LIB文件
LIB文件:称为DLL的导入库文件,是一个特殊的库文件,和静态库文件有着本质上的区别,引入库文件包含该DLL导出的函数和变量的符号名;而DLL文件包含该DLL实际函数和数据。
工程结构:

CTest.h
#pragma once
class __declspec(dllexport) CTest
{
public:void Show();
};
Add.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus__declspec(dllexport) int Add(int n1, int n2);__declspec(dllexport) extern int g_nVal;
#ifdef __cplusplus
}
#endif // __cplusplus
Sub.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus__declspec(dllexport) int Sub(int n1, int n2);
#ifdef __cplusplus
}
#endif // __cplusplus
Add.cpp
#include "Add.h"
int Add(int n1, int n2)
{return n1 + n2;
}
int g_nVal = 0x12345678;
CTest.cpp
#include "CTest.h"
#include <iostream>
using namespace std;
void CTest::Show()
{cout << "CTest::Foo()" << endl;
}
dll.cpp
#include <iostream>
#include "CTest.h"
#include "Add.h"
#include "Sub.h"
int main()
{std::cout << Add(1, 2) << std::endl;std::cout << Sub(2, 1) << std::endl;CTest test;test.Show();
}
Sub.cpp
#include "Sub.h"
int Sub(int n1, int n2)
{return n1 - n2;
}
编译后生成以下文件:
在下面动态链接库的debug目录下:生成了dll文件;dll.exp 文件是一个输出库文件。
LIB文件:称为DLL的导入库文件,是一个特殊的库文件,和静态库文件有着本质上的区别,引入库文件包含该DLL导出的函数和变量的符号名;而DLL文件包含该DLL实际函数和数据。

查看导出函数工具-DEPENDS,拖进去使用即可

五、动态链接库的两种调用方式
动态链接库的使用
- 静态调用:在程序编译的时候将DLL的信息植入可执行文件
- 动态调用:在程序中用语句显示地加载DLL,编译器不需要知道任何关于DLL的信息。
显式加载和隐式加载是在使用动态链接库(DLL)时的两种加载方式。下面我将为你解释这两种加载方式的区别:
-
隐式加载(Implicit Loading):
- 在编译时,程序会将对 DLL 的引用嵌入到可执行文件中。
- 在程序运行时,操作系统会自动加载并初始化 DLL。
- 隐式加载不需要手动加载 DLL 或指定 DLL 的路径。
- 函数调用时,直接使用函数名进行调用,编译器会根据嵌入的引用找到对应的函数地址。
- DLL 的导入函数表会在程序加载时自动解析,可以直接访问 DLL 中的函数。
-
显式加载(Explicit Loading):
- 程序需要显式地通过代码来加载 DLL 并获取其函数地址。
- 使用
LoadLibrary函数加载 DLL,并返回一个句柄,表示已加载的 DLL。 - 使用
GetProcAddress函数根据函数名获取 DLL 中的函数地址。 - 加载后的 DLL 需要手动卸载,使用
FreeLibrary函数释放 DLL 句柄。 - 函数调用时,需要通过函数指针来调用 DLL 中的函数。
显式加载和隐式加载主要的区别在于加载时机和加载方式。隐式加载在程序运行时自动加载 DLL,并且可以直接调用 DLL 中的函数。而显式加载需要手动加载 DLL,并使用函数指针来调用 DLL 中的函数。显式加载提供了更大的灵活性和控制权,适用于需要在运行时动态加载和卸载 DLL 的情况,而隐式加载则更加简单和方便。
六、动态链接库的静态加载
静态调用步骤:
- 新建应用工程。
- 通过编译器供给应用程序关于DLL的名称,以及DLL函数的链接参考(.h文件)。这种方式不需要在程序中用代码将DLL加载到内存。
- 将DLL和LIB文件拷贝到工程目录下
- 将lib文件添加到工程
- 方式一:项目>>属性>>链接>>依赖项>>lib名称
- 方式二:拖入到项目
- 添加头文件>>直接调用头文件中的函数即可。
新建一个控制台项目,目录结构如下

Add.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus__declspec(dllimport) int Add(int n1, int n2);__declspec(dllimport) extern int g_nVal;
#ifdef __cplusplus
}
#endif // __cplusplus
Sub.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus__declspec(dllimport) int Sub(int n1, int n2);
#ifdef __cplusplus
}
#endif // __cplusplus
CTest.h
#pragma once
class __declspec(dllimport) CTest
{
public:void Show();
};
.cpp
#include <iostream>
#include "CTest.h"
#include "Add.h"
#include "Sub.h"
#pragma comment(lib,"dll.lib")int main()
{std::cout << Add(1, 2) << std::endl;std::cout << Sub(3, 4) << std::endl;std::cout << std::hex << g_nVal << std::endl;CTest test;test.Show();
}
动态链接库与可执行文件放在同一目录下:

lib文件放到根目录下

方式一:使用 extern 声明外部函数
extern 关键字在C和C++中都有着重要的作用,它的具体含义取决于它所修饰的变量或函数。
在C语言中,extern 关键字用于声明一个变量或函数是在别处定义的,告诉编译器该变量或函数的定义在其他地方,不在当前文件中。具体来说:
-
外部变量声明:在C语言中,当你在一个文件中使用了一个全局变量,而该变量的定义在另外一个文件中时,你可以使用
extern来声明该变量,以便编译器知道该变量的定义在其他地方。// 在一个文件中声明外部变量 extern int global_var; // 声明global_var是在其他文件中定义的全局变量 -
外部函数声明:
extern也可以用于声明外部函数,在这种情况下,它告诉编译器该函数的定义在其他地方,不在当前文件中。// 外部函数声明 extern void external_function(); // 声明external_function是在其他文件中定义的函数


方式二:__declspec(dllimport) 声明外部函数
除了使用extern 关键字表明函数是外部定义的之外,还可以使用标识符:__declspec(dllimport) 来表明函数是从动态链接库中引入的。
__declspec(dllimport) 与使用extern 关键字这种方式相比,再使用__declspec(dllimport) 标识符声明外部函数时,它将告诉编译器该函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码。所以调用的函数来自于动态链接库,则应该使用这种方式来声明外部函数。



标准来说,无论是全局变量,还是函数都是需要使用关键字dllimport
使用宏优化导关键字dllimport
代码如下:
#pragma once
#ifdef DLL_EXPORT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
解释一下这段代码的含义:
-
#ifdef DLL_EXPORT:这个条件编译指令用于检查是否定义了DLL_EXPORT宏。如果定义了,表示当前是在编译DLL库的源代码,需要导出函数和数据。如果没有定义,则表示当前是在使用DLL的客户端代码,需要导入函数和数据。 -
#define DLL_API __declspec(dllexport):如果DLL_EXPORT被定义了,那么将DLL_API宏定义为__declspec(dllexport)。__declspec(dllexport)是在Windows平台上用于标记要导出的函数和数据的修饰符。 -
#else:如果DLL_EXPORT未被定义,执行下面的代码块。 -
#define DLL_API __declspec(dllimport):将DLL_API宏定义为__declspec(dllimport)。__declspec(dllimport)是在Windows平台上用于标记要导入的函数和数据的修饰符。
通过这种方式,可以在编写DLL库时使用DLL_API宏来修饰要导出的函数和数据,而在使用DLL库的客户端代码中使用DLL_API宏来修饰要导入的函数和数据。这样可以保证在编译时正确地处理导出和导入函数的修饰符。
动态链接库创建优化

预处理器包含宏:DLL_EXPORT

DLL_API 替换 __declspec(dllexport),并包含 common.h 头文件

加载动态链接库优化
不需要包含这个宏即可, .h 文件 包含 common.h 文件 替换宏即可


读取全局变量来说,最好直接无脑加 extern 关键字
补充:在实现动态链接库时,可以不导出整个类,而只导出该类中的某些函数,在导出类的成员函数的时候需要注意,该函数必须具有public类型的访问权限。
兼容 C
如果使用C++语言编写了一个DLL,那么使用C语言编写的客户端程序访问DLL中的函数就会出现问题,因为后者将使用函数原始名称来调用DLL中的函数,而C++编译器已经对该名称进行了改编,所以C语言编写的客户端程序就找不到所需的DLL导出函数。
#pragma once
#ifdef DLL_EXPORT
#define DLL_API extern "C" __declspec(dllexport)
#else
#define DLL_API extern "C" __declspec(dllimport)
#endif
利用限定符 extern “C” 可以解决C++和C语言之间的相互调用是函数命名问题。但是这种方法有一个缺陷,就是不能用于导出一个类的成员函数和全局变量,只能用于导出全局函数这种情况。
如果导出函数的调用约定发生了变化,那么即使使用了限定符 extern “C” ,该函数的名字仍然会发生改编。
在这种情况下,可以通过一个称为模块定义文件(DEF) 的方式来解决名字改编问题。
相关文章:
Windows核心编程 静态库与动态库
资源文件 .rc 文件 会被 rc.exe 变成 .res 文件(二进制文件) 在链接时链接进入 .exe 文件 一、如何保护源码 程序编译链接过程 不想让别人拿到源代码,但是想让其使用功能,根据上图观察,把自己生成的obj给对方,对方拿到obj后&…...
【Spring Boot】如何自定义序列化以及反序列器
在我们使用默认的消息转换器,将java的Long类型通过json数据传输到前端JS时,会导致Long类型的精度丢失,这是因为JS处理Long类型数字只能精确到前16位,所以我们可以采用自定义序列化方式将Long类型数据统一转为String字符串…...
6 Redis的慢查询配置原理
1、redis的命令执行流程 redis的慢查询只针对步骤3 默认情况下,慢查询的阈值是10ms...
JAVA小游戏 “拼图”
第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 创建一个代码类 和一个运行类 代码如下: package heima; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import …...
Spring 配置
配置文件最主要的目的 : 解决硬编码的问题(代码写死) SpringBoot 的配置文件,有三种格式 1.properties 2.yaml 3.yml(是 yaml 的简写) SpringBoot 只支持三个文件 1.application.properties 2.application.yaml 3.application.yml yaml 和 yml 是一样的,学会一个就行…...
全新酷盒9.0源码:多功能工具箱软件的最新iapp解决方案
全能工具箱软件酷盒:源码提供iapp解决方案,自定义打造个性化体验 酷盒是一款功能丰富的工具箱软件,内置众多实用功能,并实时更新热门功能。该软件还拥有丰富的资源库,用户可以在线畅玩游戏、免费下载音乐等。 我们提…...
aspose.cells java合并多个excel
背景 有需求需要把多个excel合并到一个excel文件里面,之前一直都是用python来处理办公自动化的东西,但是这个需求用python的openxyl库处理基本只能合并数据,样式没办法一比一合并过去,找了很多解决方案都没法实现,所以…...
【每日一题】三个无重叠子数组的最大和
文章目录 Tag题目来源题目解读解题思路方法一:滑动窗口 写在最后 Tag 【滑动窗口】【数组】【2023-11-19】 题目来源 689. 三个无重叠子数组的最大和 题目解读 解题思路 方法一:滑动窗口 单个子数组的最大和 我们先来考虑一个长度为 k 的子数组的最…...
react之基于@reduxjs/toolkit使用react-redux
react之基于reduxjs/toolkit使用react-redux 一、配置基础环境二、使用React Toolkit 创建 counterStore三、为React注入store四、React组件使用store中的数据五、实现效果六、提交action传递参数七、异步状态操作 一、配置基础环境 1.使用cra快速创建一个react项目 npx crea…...
基于51单片机水位监测控制报警仿真设计( proteus仿真+程序+设计报告+讲解视频)
这里写目录标题 💥1. 主要功能:💥2. 讲解视频:💥3. 仿真💥4. 程序代码💥5. 设计报告💥6. 设计资料内容清单&&下载链接💥[资料下载链接:](https://doc…...
git基本用法和操作
文章目录 创建版本库方式:Git常用操作命令:远程仓库相关命令分支(branch)操作相关命令版本(tag)操作相关命令子模块(submodule)相关操作命令忽略一些文件、文件夹不提交其他常用命令 创建版本库方式: 创建文件夹 在目录下 右键 Git Bush H…...
设计模式-组合模式-笔记
“数据结构”模式 常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定数据结构,将极大地破坏组件的复用。这时候,将这些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访…...
Android 弹出自定义对话框
Android在任意Activity界面弹出一个自定义的对话框,效果如下图所示: 准备一张小图片,右上角的小X图标64*64,close_icon.png,随便找个小图片代替; 第一步:样式添加,注意:默认在value…...
(论文阅读40-45)图像描述1
40.文献阅读笔记(m-RNN) 简介 题目 Explain Images with Multimodal Recurrent Neural Networks 作者 Junhua Mao, Wei Xu, Yi Yang, Jiang Wang, Alan L. Yuille, arXiv:1410.1090 原文链接 http://arxiv.org/pdf/1410.1090.pdf 关键词 m-RNN、…...
4核8G服务器价格选择轻量还是CVM合适?
腾讯云服务器4核8G配置优惠价格表,轻量应用服务器和CVM云服务器均有活动,云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元,5年6490.44元,轻量应用服务器4核8G12M带宽一年446元、529元15个月,腾讯云百科txybk.com分…...
Selenium操作已经打开的Chrome浏览器窗口
Selenium操作已经打开的Chrome浏览器窗口 0. 背景 在使用之前的代码通过selenium操作Chrome浏览器时,每次都要新打开一个窗口,觉得麻烦,所以尝试使用 Selenium 获取已经打开的浏览器窗口,在此记录下过程 本文使用 chrome浏览器来…...
创新研报|新业务发展是CEO推动企业增长的必要选择 – Mckinsey研究
🔍📈 创新研究报告 |新业务拓展:CEO推动企业成长的必然选择 – 麦肯锡研究 🔥💼 所有执行长和商界领袖请注意!您是否正在寻找为您的组织释放成长机会的钥匙? 🌐 麦肯锡最近的一份研究…...
rv1126-rv1109-openssh
这是一个工具,可以通过ssh远程登录来操作,非常逆天! 于是rv1109代码自身自带有openssh 所以只需要打开config即可 diff --git a/buildroot/configs/rockchip_rv1126_rv1109_spi_nand_defconfig b/buildroot/configs/rockchip_rv1126_rv1109…...
MySQL中json类型,你使用过吗
在最近的项目开发过程中,遇到了消息发送内容以Map形式存储的情况。最初的解决方案是将对象转换为字符串,并存储在MySQL的varchar(3000)字段中。然而,由于对存储空间的限制,不得不寻找其他解决方案。在调研中发现,从MyS…...
MATLAB 状态空间设计 —— LQG/LQR 和极点配置算法
系列文章目录 文章目录 系列文章目录前言一、相关函数 —— LQG/LQR 和极点配置算法1.1 LQR —— lqr 函数1.1.1 函数用法1.1.2 举例1.1.2.1 倒摆模型的 LQR 控制 1.2 LQG —— lqg() 函数1.2.1 函数用法1.2.2 举例 1.3 极点配置 —— place() 函数1.3.1 函数用法1.3.2 示例1.3…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
