Linux 开发环境以及编译链接
再谈编译链接
C++函数重载与编译链接-CSDN博客
之前我已经写过文章简单介绍了编译链接要做的一些操作。现在为了能更好的理解我们平时的开发环境,我会在Linux系统上完整地走一遍流程。
环境描述
我们使用普通用户在Linux上进行操作,先写一段测试代码。
[ssddffaa@code code]$ vim test.c#include <stdio.h>int main()
{printf("Hello World!\n");return 0;
}
接下来我们使用 gcc 编译器编译一下我们的文件。
[ssddffaa@code code]$ gcc test.c
[ssddffaa@code code]$ ls
a.out test.c
[ssddffaa@code code]$ ll
total 16
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:32 a.out
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
[ssddffaa@code code]$
可以看到默认生成了一个带可执行权限的文件 a.out ,接着我们运行它。
[ssddffaa@code code]$ ./a.out
Hello World!
要是不想要默认生成的可执行文件,我们也可以使用 gcc 的 "-o" 参数改变 gcc 的输出。
[ssddffaa@code code]$ gcc test.c -o test.txt
[ssddffaa@code code]$ ll
total 28
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:32 a.out
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 09:36 test.txt[ssddffaa@code code]$ ./test.txt
Hello World!
可以看到我们重新生成了一个可执行文件 test.txt。可能你会疑惑,这个文件的后缀名是 "txt" 怎么还能执行?他不应该是一个记事本嘛?
在Linux系统中文件是否能被运行有两个条件,一是文件具有可执行权限,二是文件本身具有可执行的功能。以上两个条件我们的 text.txt 都满足了,当然可以正常执行。相对的如果一个文件只有可执行权限,但是文件本身本没有可执行能力,那也是执行不了的。
编译链接
预处理
下面我们来看一看 test.c 文件经过预处理后会发生什么。通过 gcc 加 "-E" 参数可以使文件编译到预处理阶段完成后就停止,并把结果打印到屏幕上,使用 "-o" 参数可以重定向到指定文件中。
[ssddffaa@code code]$ gcc -E test.c -o test.i
[ssddffaa@code code]$ ll
total 24
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i[ssddffaa@code code]$ vim test.i
825 extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
826 # 913 "/usr/include/stdio.h" 3 4
827 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
828
829
830
831 extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
832
833
834 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
835 # 943 "/usr/include/stdio.h" 3 4
836
837 # 2 "test.c" 2
838
839 int main()
840 {
841
842 printf("Hello World!\n");
843 return 0;
844 }
当我们进入 test.i 文件中进行查看时,会发现原本我们只写了几行的代码在 test.i 文件中增加到了800多行。我们多出来的这些代码是什么呢?我想你应该已经猜到了,这是预处理阶段要做的一件事 "头文件展开"。没错,多出来的这几百行代码就是 #include <stdio.h> 的效果,那么这些代码是凭空出现的嘛,显然不是。头文件展开其实就是去把Linux系统中的头文件内容拷贝了一份然后放进了我们的代码。
我们可以在系统中找一下存放头文件的位置。
[ssddffaa@code code]$ sudo find / -name stdio.h
[sudo] password for ssddffaa:
/usr/include/c++/4.8.2/tr1/stdio.h
/usr/include/bits/stdio.h
/usr/include/stdio.h
出现了3个路径不过只有最下面那个才是我们使用的头文件,这一点可以通过查看 gcc 的默认include路径了解。
[ssddffaa@code include]$ `gcc -print-prog-name=cc1plus` -v
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/usr/local/include/usr/include
End of search list.
可以看到,我们包含的头文件确确实实是存在在我们的计算机上的。平时我们使用的 printf 等函数,并没有我们自己实现但是我们就在使用了,这是因为我们包含了头文件,然后在预处理时编译器会把我们包含的头文件内容拷贝到我们写的代码里,然后在之后的编译阶段编译器才能识别到 printf 等库函数接着进行下一步操作。
预处理阶段不仅仅只是展开头文件还有以下内容。
#1 将#define删除,并且展开所有的宏定义
#2 处理条件编译,#if #ifdef #elif #endif等
#3 头文件展开
#4 删除注释
#5 添加行号和文件标识,以便编译时产生调试试用的行号以及编译错误警告号
#6 保留所有的#pragma编译器指令,因为编译器需要使用它们
编译
预处理完成后会进入编译阶段,在这个阶段我们之前处理过的 test.i 文件会进一步进行处理。编译阶段在整个编译链接中是最复杂的一个。
编译过程可以分为6步:
#1 词法分析:扫描器(Scanner)将源代的字符序列分割成一系列的记号(Token)
#2 语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)
#3 语义分析:静态语义(编译器可以确定的语义),动态语义(只能在运行期才能确定的语义)
#4 源代码优化:源代码优化器,将整个语法树转换为中间代码(中间代码是与目标机器和运行环境无关的)中间使得编译器被分为前端和后端,编译器前端负责产生机器无关的中间代码编译器后端将中间代码转化为目标机器代码
#5 目标代码生成:代码生成器(Code Generator)
#6 目标代码优化:目标代码优化器(Target Code Optimizer)
我们代码语法的检查,代码的优化等都是在编译阶段完成的。在编译阶段还会生成符号表,它用于链接阶段。
使用 gcc 加 "-S" 参数可以让文件编译执行到编译阶段完成后终止。
[ssddffaa@code code]$ gcc -S test.c -o test.s
[ssddffaa@code code]$ ll
total 28
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:23 test.s[ssddffaa@code code]$ vim test.s1 .file "test.c"2 .section .rodata3 .LC0:4 .string "Hello World!"5 .text6 .globl main7 .type main, @function8 main:9 .LFB0:10 .cfi_startproc11 pushq %rbp12 .cfi_def_cfa_offset 1613 .cfi_offset 6, -1614 movq %rsp, %rbp15 .cfi_def_cfa_register 616 movl $.LC0, %edi17 call puts18 movl $0, %eax19 popq %rbp20 .cfi_def_cfa 7, 821 ret22 .cfi_endproc23 .LFE0:24 .size main, .-main25 .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"26 .section .note.GNU-stack,"",@progbits
可以看到 test.s 文件里是汇编代码。
汇编阶段
在汇编阶段,汇编器将 test.s 文件翻译成机器语言指令,把这些指令打包成一种叫做可重定位二进制目标程序的格式,并将结果保存在目标文件 test.o 中,test.o 是一个二进制文件。
使用 gcc 加 "-c" 参数可以让文件编译执行到汇编阶段完成后终止。
[ssddffaa@code code]$ gcc -c test.c -o test.o
[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:33 test.s[ssddffaa@code code]$ vim test.o
使用 vim 文本编辑器进入 test.o 查看会全是乱码,这是因为 test.o 中是二进制数据,而 vim 只能识别文本,所以我们换一个工具进行查看。
[ssddffaa@code code]$ hexdump test.o
可以看到文件由二进制转为16进制的内容。我们的计算机能识别二进制,而我们的 test.o 文件就是一个二进制文件那我们可以不可以运行它呢?我们来试一下。
[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:33 test.s
[ssddffaa@code code]$ chmod +x test.o
[ssddffaa@code code]$ ll
total 32
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rwxrwxr-x. 1 ssddffaa ssddffaa 1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:33 test.s
[ssddffaa@code code]$ ./test.o
-bash: ./test.o: cannot execute binary file
可以看到报了错误 "无法执行的二进制文件"。汇编生成的二进制文件还不具有可执行的能力,这是因为缺少了库文件。我们在预处理阶段包含的头文件只是声明,声明和定义是分离的,定义是存储在库文件中的,同时库中还包含了许多方法。
链接
汇编过后生成的目标文件(*.o)并不是最终的可执行二进制文件,而是一种中间文件(或临时文件),目标文件任然需要经过链接才能变成可执行文件。
在链接阶段,链接器会把我们写的所有目标文件(*.o)与系统组件(标准库,动态链接库等)结合起来生成一个可执行程序。(链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件)。
[ssddffaa@code code]$ gcc test.c -o test
[ssddffaa@code code]$ ll
total 44
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 16872 Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 1496 Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:33 test.s
[ssddffaa@code code]$ ./test
Hello World!
Linux下的C语言的标准库文件在 "/usr/lib64/" 下本质就是一个文件。
[ssddffaa@code code]$ ll /usr/lib64/libc.so*
-rw-r--r--. 1 root root 253 May 18 2022 /usr/lib64/libc.so
lrwxrwxrwx. 1 root root 12 Mar 27 08:53 /usr/lib64/libc.so.6 -> libc-2.17.so
Linux和Windows下的库文件。
# Linux: .so(动态库) .a(静态库)
# Windows .dll(动态库) .lib(静态库)库的命名规则
# libname.so.XXX
# 其中lib是库前缀名,name则是库的名称,so是库后缀,XXX是版本号
编译型语言,安装开发包,必定是下载安装对应的头文件和库文件。
库其实就是把源文件(.c),经过一定的翻译,然后打包形成一个文件。不用给你提供太多的源文件,也可以达到隐藏源文件的目的。
头文件提供声明,库文件提供实现 + 你的代码 = 你的软件。
动态链接与静态链接
库有动态库和静态库,链接也有动态链接和静态链接。
动态链接
动态库是一个共享的库文件,当程序开始执行时编译器便会告诉程序动态库在哪个位置,有哪些方法。当程序执行到需要库里的文件时便会跑到库里去执行,执行完又继续执行下一步操作。像这样编译器告诉程序动态库的位置,然后程序需要时跑去执行的方式叫动态链接。
动态库不能缺失,一旦对应的动态库缺失,影响的不止一个程序,可能导致很多程序都无法正常运行。
静态链接
静态链接就相当于直接把静态库中要用到的内容直接和我们的目标文件链接在一起生成可执行程序。完成后,就算静态库没了程序也能正常运行。
比较
动态链接和静态链接各有各的优势,当一个库文件有许多程序都需要使用时,用动态链接可以让程序不用去每个都拷贝一份库文件。而且更新库文件时方便,你只需要改库文件就可以完成库的更新。
静态链接可以让程序不依赖之前的静态库文件,减少重定向链接到动态库的开销提高了程序效率。但是这个效率只提高了5%左右。更新库时麻烦,需要重新修改静态库文件,然后再编译链接一次生成新的可执行文件。
验证
使用 "ldd" 可以查看程序的动态链接情况
[ssddffaa@code code]$ ldd testlinux-vdso.so.1 => (0x00007ffc36b9c000)libc.so.6 => /lib64/libc.so.6 (0x00007f4ff73f3000)/lib64/ld-linux-x86-64.so.2 (0x00007f4ff77c1000)
可以看到,在Linux下 gcc 默认使用的是动态链接。 在编译时加上 "-static" 参数可以让 gcc 使用静态链接。
[ssddffaa@code code]$ gcc test.c -o test-static -static
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
报错了,这个报错的原因呢是因为我们的Linux系统上默认是没有静态库的,需要我们手动去安装一下。
[ssddffaa@code code]$ sudo yum install -y glibc-static
[ssddffaa@code code]$ sudo yum install -y libstdc++-static
安装完成后我们再去试一下。
[ssddffaa@code code]$ gcc test.c -o test-static -static
[ssddffaa@code code]$ ll -h
total 888K
-rwxrwxr-x. 1 ssddffaa ssddffaa 8.2K Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rw-rw-r--. 1 ssddffaa ssddffaa 17K Mar 28 09:45 test.i
-rw-rw-r--. 1 ssddffaa ssddffaa 1.5K Mar 28 20:40 test.o
-rw-rw-r--. 1 ssddffaa ssddffaa 448 Mar 28 20:33 test.s
-rwxrwxr-x. 1 ssddffaa ssddffaa 842K Mar 29 01:41 test-static
[ssddffaa@code code]$ ldd test-static not a dynamic executable
可以看到成功生成了一个可执行程序 test-static,并且它没有使用任何动态库。但是 test-static 和 test 的大小起来大了80K左右。
#1 如果我们没有静态库,但是我们就要-static,是不行的
#2 如果我们没有动态库,只有静态库,而且gcc能找到不使用-staticgcc还是会链接成功,并且使用静态库这是因为gcc默认使用动态链接,使用-static只是增加了静态链接的优先级
#3 不一定是纯的全部动态链接或静态链接,是混合的
查看可执行程序使用的库情况。
[ssddffaa@code code]$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=9fc19efe5a60448b3a2d19e1e150f7b77d65993a, not stripped
[ssddffaa@code code]$ file test-static
test-static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=7cd92dd71613a6bad6eea55cc7d520b28e98e9d7, not stripped
Debug && Release
Debug 模式相比 Release 模式增加了调试信息,可以方便开发人员对代码进行调试。gcc 默认使用的是 Release 模式,要使用 Debug 模式需要加上参数 "-g"。
[ssddffaa@code code]$ gcc test.c -o test_debug -g
[ssddffaa@code code]$ gcc test.c -o test-static_debug -static -g
[ssddffaa@code code]$ ll
total 1716
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 28 21:47 test
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa 9360 Mar 29 02:09 test_debug
-rwxrwxr-x. 1 ssddffaa ssddffaa 861288 Mar 29 01:41 test-static
-rwxrwxr-x. 1 ssddffaa ssddffaa 862296 Mar 29 02:10 test-static_debug
可以看到 Debug 模式生成的可执行程序都比 Release 模式下生成的可执行程序大,这是因为 Debug 模式增加了调试信息。
[ssddffaa@code code]$ readelf -S test_debug | grep debug[27] .debug_aranges PROGBITS 0000000000000000 00001061[28] .debug_info PROGBITS 0000000000000000 00001091[29] .debug_abbrev PROGBITS 0000000000000000 00001122[30] .debug_line PROGBITS 0000000000000000 00001164[31] .debug_str PROGBITS 0000000000000000 0000119f
make/Makefile
一个工程中的源文件不计其数,按类型、功能、模块分别放在若干个目录中,Makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
make是一条指令,Makefile是一个当前目录下的文件。
[ssddffaa@code code]$ touch Makefile
[ssddffaa@code code]$ vim Makefile1 test.exe:test.c #编写 Makefile 第一行是依赖关系2 gcc -o test.exe test.c #第二行是以TAB开始然后输入依赖方法。3 .PHONY:clean #加上PHONY参数修饰clean4 clean: #清理5 rm -f test.exe #清理方法
通过 make 指令来执行 Makefile 文件内容。
[ssddffaa@code code]$ make
gcc -o test.exe test.c
[ssddffaa@code code]$ ll
total 20
-rw-rw-r--. 1 ssddffaa ssddffaa 40 Mar 29 02:41 Makefile
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
-rwxrwxr-x. 1 ssddffaa ssddffaa 8360 Mar 29 02:41 test.exe
[ssddffaa@code code]$ ./test.exe
Hello World!
[ssddffaa@code code]$ make clean
rm -f test.exe
[ssddffaa@code code]$ ll
total 8
-rw-rw-r--. 1 ssddffaa ssddffaa 76 Mar 29 02:50 Makefile
-rw-rw-r--. 1 ssddffaa ssddffaa 75 Mar 28 09:31 test.c
可以看出 make/Makefile 能把我们从冗余的 gcc 命令中解脱出来,只需 make 和 make clean 就可以构建和删除项目。
参考文章
程序详细编译过程(预处理、编译、汇编、链接) - 知乎 (zhihu.com)
详解C/C++代码的预处理、编译、汇编、链接全过程 - 知乎 (zhihu.com)
深入浅出静态链接和动态链接-CSDN博客
相关文章:
Linux 开发环境以及编译链接
再谈编译链接 C函数重载与编译链接-CSDN博客 之前我已经写过文章简单介绍了编译链接要做的一些操作。现在为了能更好的理解我们平时的开发环境,我会在Linux系统上完整地走一遍流程。 环境描述 我们使用普通用户在Linux上进行操作,先写一段测试代码。 …...
SmartChart的部署以及可能遇见的报错解决方案
简介 数据可视化是一种将数据转化为图形的技术,可以帮助人们更好地理解和分析数据。但是,传统的数据可视化开发往往需要编写大量的代码,或者使用复杂的拖拽工具,不仅耗时耗力,而且难以实现个性化的需求。有没有一种更…...
【Node.js从基础到高级运用】十九、Node.js 捕获错误之“未捕获的异常”
引言 在 Node.js 应用程序中,错误处理是保证应用稳定性和可靠性的关键部分。特别是“未捕获的异常”(uncaught exceptions),如果不妥善处理,很可能会导致整个进程崩溃。在本文中,我们将探讨如何在 Node.js …...
vue 计算属性
基础示例 模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象: const author reactive({name: John Doe,books: [V…...
RedissonLock-tryLock-续期
redisson版本3.16.6 1.什么是看门狗 Redisson提供的分布式锁是支持锁自动续期的,也就是说,如果线程仍旧没有执行完,那么redisson会自动给redis中的目标key延长超时时间,这在Redisson中称之为 Watch Dog 机制。默认情况下&#x…...
MSTP环路避免实验(华为)
思科设备参考:MSTP环路避免实验(思科) 一,技术简介 MSTP(多生成树协议),MSTP解决了STP和RSTP没有考虑vlan的问题,STP和RSTP将所有的vlan共享为一个生成树实例,无法实现…...
IoT网关在智能制造工厂生产线监控与管理中的应用-天拓四方
随着工业4.0时代的到来,智能制造已成为工业发展的重要方向。IoT网关在智能制造工厂中扮演着关键角色,它能够实现设备间的互联互通、数据的实时采集与处理,以及生产线的智能监控与管理。本案例将详细介绍IoT网关在智能制造工厂生产线监控与管理…...
niushop单商户V5多店版源码分享三端uniapp打包方法包括PC端_小程序或h5端打包_收银端打包_APP端打包_商户端
目前多店版有四端uniapp,包括PC端uniapp,商家端uniapp,收银端uniapp,门店手机端uniapp,下面我总结下这些端的打包流程希望能帮助到大家,需要交流的可以看我昵称或者点我头像关注我分享代码和教程 一.niush…...
npm包发布
一、npm npm(Node Package Manager)是 Node.js 的包管理工具,用于安装、分享和管理 JavaScript 包和项目依赖。npm 是 Node.js 的默认包管理器,随同 Node.js 一起安装。 二、npm主要功能特点 包管理:npm 允许开发者…...
C#使用SQLite(含加密)保姆级教程
C#使用SQLite 文章目录 C#使用SQLite涉及框架及库复制runtimes创建加密SQLite文件生成连接字串执行SQL生成表SQLiteConnectionFactory.cs 代码结构最后 涉及框架及库 自己在NuGet管理器里面安装即可 Chloe.SQLite:ORM框架Microsoft.Data.Sqlite.Core:驱…...
C# 异步与 Unity 协程(实例讲解)
C#异步编程实例: 假设我们有一个需要从Web获取数据的简单应用。我们可以使用C#的异步编程模型来避免UI线程被HTTP请求阻塞 1using System.Net.Http; 2using System.Threading.Tasks; 3 4public class AsyncExample 5{ 6 public async Task<string> Fetch…...
iOS - Runloop介绍
文章目录 iOS - Runloop介绍1. 简介1.1 顾名思义1.2. 应用范畴1.3. 如果没有runloop1.4. 如果有了runloop 2. Runloop对象3. Runloop与线程4. 获取Runloop对象4.1 Foundation4.2 Core Foundation4.3 示例 5. Runloop相关的类5.1 Core Foundation中关于RunLoop的5个类5.2 CFRunL…...
探究分布式事务:深入ACID特性在分布式系统中的挑战与解决方案
✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 🎈🎈作者主页: 喔的嘛呀🎈🎈 ✨✨ 帅哥美女们,我们共同加油!一起进步&am…...
PCI总线管脚定义(引脚定义)
文章目录 1: 参考资料的链接2: 图片说明3:PCI文字说明每日好图 1: 参考资料的链接 PCI bus pinout PCI三种标准引脚信号定义 PCI bus pinout 2: 图片说明 A面和B面正反 PCI Universal Card 32/64 bit ----------------------------------…...
万字详解PHP+Sphinx中文亿级数据全文检索实战(实测亿级数据0.1秒搜索耗时)
Sphinx查询性能非常厉害,亿级数据下输入关键字,大部分能在0.01~0.1秒,少部分再5秒之内查出数据。 Sphinx 官方文档:http://sphinxsearch.com/docs/sphinx3.html极简概括: 由C编写的高性能全文搜索引擎的开源组件&…...
数据库索引及优化
数据库索引及优化 什么是索引? MySQL官方对索引的定义为:索引(INDEX)是帮助MySQL高效获取数据的数据结构。 索引的本质: 数据结构 为什么要引入索引? 引入索引的目的在于提高查询效率,就好像是…...
flink: 将接收到的tcp文本流写入HBase
一、依赖: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…...
SpringBoot集成knife4j
SpringBoot集成knife4j 1、什么是Knife4j2、SpringBoor整合Knife4j2.1、Knife4j配置方式12.2 配置方式二2.3、写注解2.4、效果 1、什么是Knife4j 在日常开发中,写接口文档是我们必不可少的,而Knife4j就是一个接口文档工具,可以看作是Swagger…...
Vue3之setup方法
Vue 3 的 setup 方法是 Vue Composition API 的一部分,用于组织和复用 Vue 组件的逻辑代码。Vue Composition API 允许您以更具响应性和函数式的方式来组织和复用 Vue 组件中的代码,特别是在处理复杂逻辑或跨组件共享逻辑时非常有用。 以下是关于 setup…...
MySQL常见索引及其创建
MySQL索引 在 MySQL 数据库中,常见的索引类型包括以下几种: 普通索引(Normal Index):最基本的索引类型,没有任何限制。唯一索引(Unique Index):要求索引列的值是唯一的…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
