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

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博客 之前我已经写过文章简单介绍了编译链接要做的一些操作。现在为了能更好的理解我们平时的开发环境&#xff0c;我会在Linux系统上完整地走一遍流程。 环境描述 我们使用普通用户在Linux上进行操作&#xff0c;先写一段测试代码。 …...

SmartChart的部署以及可能遇见的报错解决方案

简介 数据可视化是一种将数据转化为图形的技术&#xff0c;可以帮助人们更好地理解和分析数据。但是&#xff0c;传统的数据可视化开发往往需要编写大量的代码&#xff0c;或者使用复杂的拖拽工具&#xff0c;不仅耗时耗力&#xff0c;而且难以实现个性化的需求。有没有一种更…...

【Node.js从基础到高级运用】十九、Node.js 捕获错误之“未捕获的异常”

引言 在 Node.js 应用程序中&#xff0c;错误处理是保证应用稳定性和可靠性的关键部分。特别是“未捕获的异常”&#xff08;uncaught exceptions&#xff09;&#xff0c;如果不妥善处理&#xff0c;很可能会导致整个进程崩溃。在本文中&#xff0c;我们将探讨如何在 Node.js …...

vue 计算属性

基础示例​ 模板中的表达式虽然方便&#xff0c;但也只能用来做简单的操作。如果在模板中写太多逻辑&#xff0c;会让模板变得臃肿&#xff0c;难以维护。比如说&#xff0c;我们有这样一个包含嵌套数组的对象&#xff1a; const author reactive({name: John Doe,books: [V…...

RedissonLock-tryLock-续期

redisson版本3.16.6 1.什么是看门狗 Redisson提供的分布式锁是支持锁自动续期的&#xff0c;也就是说&#xff0c;如果线程仍旧没有执行完&#xff0c;那么redisson会自动给redis中的目标key延长超时时间&#xff0c;这在Redisson中称之为 Watch Dog 机制。默认情况下&#x…...

MSTP环路避免实验(华为)

思科设备参考&#xff1a;MSTP环路避免实验&#xff08;思科&#xff09; 一&#xff0c;技术简介 MSTP&#xff08;多生成树协议&#xff09;&#xff0c;MSTP解决了STP和RSTP没有考虑vlan的问题&#xff0c;STP和RSTP将所有的vlan共享为一个生成树实例&#xff0c;无法实现…...

IoT网关在智能制造工厂生产线监控与管理中的应用-天拓四方

随着工业4.0时代的到来&#xff0c;智能制造已成为工业发展的重要方向。IoT网关在智能制造工厂中扮演着关键角色&#xff0c;它能够实现设备间的互联互通、数据的实时采集与处理&#xff0c;以及生产线的智能监控与管理。本案例将详细介绍IoT网关在智能制造工厂生产线监控与管理…...

niushop单商户V5多店版源码分享三端uniapp打包方法包括PC端_小程序或h5端打包_收银端打包_APP端打包_商户端

目前多店版有四端uniapp&#xff0c;包括PC端uniapp&#xff0c;商家端uniapp&#xff0c;收银端uniapp&#xff0c;门店手机端uniapp&#xff0c;下面我总结下这些端的打包流程希望能帮助到大家&#xff0c;需要交流的可以看我昵称或者点我头像关注我分享代码和教程 一.niush…...

npm包发布

一、npm npm&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;用于安装、分享和管理 JavaScript 包和项目依赖。npm 是 Node.js 的默认包管理器&#xff0c;随同 Node.js 一起安装。 二、npm主要功能特点 包管理&#xff1a;npm 允许开发者…...

C#使用SQLite(含加密)保姆级教程

C#使用SQLite 文章目录 C#使用SQLite涉及框架及库复制runtimes创建加密SQLite文件生成连接字串执行SQL生成表SQLiteConnectionFactory.cs 代码结构最后 涉及框架及库 自己在NuGet管理器里面安装即可 Chloe.SQLite&#xff1a;ORM框架Microsoft.Data.Sqlite.Core&#xff1a;驱…...

C# 异步与 Unity 协程(实例讲解)

C#异步编程实例&#xff1a; 假设我们有一个需要从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特性在分布式系统中的挑战与解决方案

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起进步&am…...

PCI总线管脚定义(引脚定义)

文章目录 1&#xff1a; 参考资料的链接2: 图片说明3&#xff1a;PCI文字说明每日好图 1&#xff1a; 参考资料的链接 PCI bus pinout PCI三种标准引脚信号定义 PCI bus pinout 2: 图片说明 A面和B面正反 PCI Universal Card 32/64 bit ----------------------------------…...

万字详解PHP+Sphinx中文亿级数据全文检索实战(实测亿级数据0.1秒搜索耗时)

Sphinx查询性能非常厉害&#xff0c;亿级数据下输入关键字&#xff0c;大部分能在0.01~0.1秒&#xff0c;少部分再5秒之内查出数据。 Sphinx 官方文档&#xff1a;http://sphinxsearch.com/docs/sphinx3.html极简概括&#xff1a; 由C编写的高性能全文搜索引擎的开源组件&…...

数据库索引及优化

数据库索引及优化 什么是索引&#xff1f; MySQL官方对索引的定义为&#xff1a;索引&#xff08;INDEX&#xff09;是帮助MySQL高效获取数据的数据结构。 索引的本质&#xff1a; 数据结构 为什么要引入索引&#xff1f; 引入索引的目的在于提高查询效率&#xff0c;就好像是…...

flink: 将接收到的tcp文本流写入HBase

一、依赖&#xff1a; <?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 在日常开发中&#xff0c;写接口文档是我们必不可少的&#xff0c;而Knife4j就是一个接口文档工具&#xff0c;可以看作是Swagger…...

Vue3之setup方法

Vue 3 的 setup 方法是 Vue Composition API 的一部分&#xff0c;用于组织和复用 Vue 组件的逻辑代码。Vue Composition API 允许您以更具响应性和函数式的方式来组织和复用 Vue 组件中的代码&#xff0c;特别是在处理复杂逻辑或跨组件共享逻辑时非常有用。 以下是关于 setup…...

MySQL常见索引及其创建

MySQL索引 在 MySQL 数据库中&#xff0c;常见的索引类型包括以下几种&#xff1a; 普通索引&#xff08;Normal Index&#xff09;&#xff1a;最基本的索引类型&#xff0c;没有任何限制。唯一索引&#xff08;Unique Index&#xff09;&#xff1a;要求索引列的值是唯一的…...

高效测量“芯”搭档 | ACM32激光测距仪应用方案

激光测距仪概述 激光测距仪是利用激光对目标的距离进行准确测定的仪器。激光测距仪在工作时向目标射出一束很细的激光&#xff0c;由光电元件接收目标反射的激光束&#xff0c;计时器测定激光束从发射到接收的时间&#xff0c;计算出从观测者到目标的距离。激光测距仪分为手持激…...

基于Hive大数据分析springboot为后端以及vue为前端的的民宿系

标题基于Hive大数据分析springboot为后端以及vue为前端的的民宿系 本文介绍了如何利用Hive进行大数据分析,并结合Spring Boot和Vue构建了一个民宿管理系统。该民民宿管理系统包含用户和管理员登陆注册的功能,发布下架酒店信息,模糊搜索,酒店详情信息展示,收藏以及对收藏的…...

pnpm、monorepo分包管理、多包管理、npm、vite、前端工程化、保姆级教程

浅尝pnpm monorepo 多包管理方案 &#x1f4a1;tips: 创建pnpm monorope多包管理框架流程 初始化 mkdir taurus & cd taurus pnpm init创建基础文件 创建文件pnpm-workspace.yaml packages:- packages/**创建文件夹packages/ -packages/ -package.json -pnpm-workspace…...

vue3封装Element分页

配置当前页 配置每页条数 页面改变、每页条数改变都触发回调 封装分页 Pagination.vue <template><el-paginationbackgroundv-bind"$attrs":page-sizes"pageSizes"v-model:current-page"page"v-model:page-size"pageSize":t…...

真机 ARM64 架构转模拟器 ARM64 架构

本文字数&#xff1a;2051字 预计阅读时间&#xff1a;15分钟 01 需要转换架构的原因 老版 Mac 使用 Intel 芯片&#xff0c;是x86_64架构&#xff0c;相应地在老版 Mac 上运行的模拟器使用的也就是 x86_64架构。 由于模拟器的 x86_64 架构与真机的 arm64、armv7 等架构不冲突&…...

敏捷教练CSM认证考了有没有用,谁说了算?

敏捷教练CSM证书是近年来备受关注的一项证书&#xff0c;它被认为可以提升敏捷开发团队的管理能力和项目执行效率。然而&#xff0c;对于这个证书的价值和含金量&#xff0c;人们的观点却不尽相同。那么&#xff0c;CSM证书到底有没有用&#xff0c;谁来说了算呢&#xff1f; 首…...

Docker-Container

Docker ①什么是容器②为什么需要容器③容器的生命周期容器 OOM容器异常退出容器暂停 ④容器命令清单总览docker createdocker rundocker psdocker logsdocker attachdocker execdocker startdocker stopdocker restartdocker killdocker topdocker statsdocker container insp…...

下载安装anaconda和pytorch的详细方法,以及遇到的问题和解决办法

下载安装Anaconda 首先需要下载Anaconda&#xff0c;可以到官网Anaconda官网或者这里提供一个镜像网站去下载anaconda镜像网站 安装步骤可参考该文章&#xff1a;Anaconda安装步骤&#xff0c;本篇不再赘述 注意环境变量的配置&#xff0c;安装好Anaconda之后一定要在环境变量…...

2020年天津市二级分类土地利用数据(矢量)

天津市&#xff0c;位于华北平原海河五大支流汇流处&#xff0c;东临渤海&#xff0c;北依燕山。地势以平原和洼地为主&#xff0c;北部有低山丘陵&#xff0c;海拔由北向南逐渐下降&#xff0c;地貌总轮廓为西北高而东南低。天津有山地、丘陵和平原三种地形&#xff0c;平原约…...

设计模式——结构型——外观模式Facade

处理器类 public class Cpu {public void start() {System.out.println("处理器启动了...");} } 内存类 public class Memory {public void start() {System.out.println("内存启动了...");} } 硬盘类 public class Disk {public void start() {Syste…...

五级偏黄视频网站建设/怎么开网店新手入门

十三周五次课&#xff08;5月8日&#xff09;13.4 mysql用户管理 13.5 常用sql语句13.6 mysql数据库备份恢复 扩展 SQL语句教程 http://www.runoob.com/sql/sql-tutorial.html什么是事务&#xff1f;事务的特性有哪些&#xff1f; http://blog.csdn.net/yenange/article/detail…...

洛阳做网站的公司/sem竞价托管公司

0x01、基于mysql实现分布式锁基于分布式锁的实现&#xff0c;首先肯定是想单独分离出一台mysql数据库&#xff0c;所有服务要想操作文件(共享资源)&#xff0c;那么必须先在mysql数据库中插入一个标志&#xff0c;插入标志的服务就持有了锁&#xff0c;并对文件进行操作&#x…...

商丘网站/深圳seo网络推广

蓝桥杯 --- 二分与前缀和&#xff08;习题&#xff09;730. 机器人跳跃问题1221. 四平方和1227. 分巧克力99. 激光炸弹1230. K倍区间730. 机器人跳跃问题 机器人正在玩一个古老的基于 DOS 的游戏。 游戏中有 N1 座建筑——从 0 到 N 编号&#xff0c;从左到右排列。 编号为 …...

百度联盟/网站优化排名首页

MySQL中的索引探究 - 08/05本次分享讲述MySQL的索引原理&#xff0c;不同存储引擎对索引的支持情况。同时探究大家普遍关心的问题&#xff1a;MySQL在哪些操作中会用到索引&#xff1f;InnoDB引擎对索引做了哪些扩展&#xff1f;基于Generated Column的索引有什么用&#xff1f…...

怎么做网站的快照/澳门seo关键词排名

今天在用SQL Server 2008执行一个SQL脚本文件时&#xff0c;引发类型为“System.OutOfMemoryException”的异常错误&#xff0c;脚本明明是从SQL Server 2008导出的 出现这个错误的主要原因是由于SQL脚本文件太大&#xff0c;估计超过了100M了转载于:https://www.cnblogs.com/x…...

网站做行业认证好处/外贸获客软件

最近开始弄支付这块&#xff0c;先是支付宝手机网站支付&#xff0c;也是坑了我许久&#xff0c;不过还好&#xff0c;问题不大。 让我们看看微信支付有多少坑 微信商户平台&#xff0c;你们知道么&#xff08;我前天才知道&#xff0c;别笑我&#xff09; 登录地址&#xff1a…...