【ONE·C || 程序编译简述】
总言
C语言:程序编译相关。
文章目录
- 总言
- 1、程序的翻译环境和运行环境
- 1.1、简述
- 1.2、翻译环境:程序编译与链接
- 1.2.1、简介:程序如何从.c文件形成.exe可执行程序
- 1.2.2、过程说明
- 1.3、运行环境
- 2、预处理详解
- 2.1、预定义符号
- 2.2、#define
- 2.2.1、#define定义标识符
- 2.2.2、#define定义宏
- 2.2.3、#define替换规则介绍
- 2.2.4、#和##
- 2.2.4.1、#
- 2.2.4.2、##
- 2.2.5、 带副作用的宏参数
- 2.3、#undef
- 2.4、命令行定义
- 2.5、条件编译
- 2.5.1、格式一
- 2.5.2、格式二:多个分支的条件编译
- 2.5.3、判断是否被定义
- 2.5.4、嵌套指令
- 2.6、文件包含
- 2.6.1、头文件包含的方式
- 2.6.1.1、本地文件包含
- 2.6.1.2、库文件包含
- 2.6.2、嵌套包含
- 2.6.2.1、相关现象
- 2.6.2.2、解决方案一
- 2.6.2.3、解决方案二
1、程序的翻译环境和运行环境
1.1、简述
在ANSI C的任何一种实现中,存在两个不同的环境。
1、翻译环境:源代码被转换为可执行的机器指令。
2、执行环境:用于实际执行代码。
二者关系如下:
1.2、翻译环境:程序编译与链接
1.2.1、简介:程序如何从.c文件形成.exe可执行程序
1、组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
2、每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
3、链接器同时也会引入标准C函数库中任何被该程序所用到的函数,也可以搜索到个人程序库,将其需要的函数链接到程序中。
1.2.2、过程说明
该部分内容后续可完善。
1.3、运行环境
1. 程序要运行,则必须载入内存中。在有操作系统的环境中,这个步骤一般由操作系统完成。在独立的环境中,程序载入一般由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序载入内存后就可开始执行,其首要调用main函数。(这就是之前说的main函数是程序的入口,一个工程项目中有且仅有一个main函数。)
3、开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址,同时,程序也可以使用静态(static)内存。存储于静态内存中的变量,在程序的整个执行过程一直保留他们的值。
2、预处理详解
2.1、预定义符号
这些预定义符号都是语言内置的。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
演示例子如下:
#include <Windows.h>
int main()
{int i = 0;for (i = 0; i < 10; i++){printf("name:%s file:%s line:%d date:%s time:%s i=%d\n\n", __func__, __FILE__, __LINE__, __DATE__, __TIME__, i);Sleep(1000);}return 0;
}
如果有需要,结合文件处理所学,可以将其输出为文本文件:
#include <Windows.h>
int main()
{int i = 0;FILE* pf = fopen("log.txt", "a");if (pf == NULL){return 1;}for (i = 0; i < 10; i++){printf("name:%s file:%s line:%d date:%s time:%s i=%d\n\n", __func__, __FILE__, __LINE__, __DATE__, __TIME__, i);Sleep(1000);}fclose(pf);pf = NULL;return 0;
}
2.2、#define
#define
有两个作用,一是定义标识符,而是定义宏;
2.2.1、#define定义标识符
1)、引入
我们使用宏定义标识符,根据1中所学,可知预处理阶段会进行宏替换,现在我们来验证它:
#define NUM 100+200
#define STR "Death in the Young"int main()
{int num = NUM;char* str = STR;return 0;
}
如下图所示,左边为我们写的代码,右边则是预处理后的内容:
关于如何在VS中生成右侧.i文件,操作步骤如下:
2)、假如宏定义标识符中加入了;
,结果会怎样?
#define NUM 100+200;
#define STR "Death in the Young";
以下为我们的验证结果:
可以看到,会多形成一个语句。在上述情况下,这样子的空语句好像不会造成什么影响,但在有些场景下使用则会带来麻烦,以下为相关举例:
#define NUM 100+200;
#define STR "Death in the Young";
int main()
{int num = 0;if (1)num = NUM;elsenum = -1;return 0;
}
如图所示为宏替换后的结果,可看到if语句后,由于多了一条空语句,后续的else则没有对应匹配结果。(PS:此处并非是else就近匹配原则失效。)
3)、其它例子演示
现在我们可以来简单概括一下#define定义标识符的相关语法:
语法:#define name stuff
需要注意的是name
部分是严格按照sutff
部分定义,如果stuff
部分是一个表达式,则相应的name
部分也会变为表达式。
其它情况演示:
#define reg register //为register(寄存器)这个关键字,创建一个简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //在写case语句的时候自动把 break写上。
// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )
2.2.2、#define定义宏
1)、引入
如何用#define
定义一个宏函数?
#define Add(x,y) x+y;int main()
{int result = Add(1, 2);printf("%d\n", result);return 0;
}
可以看到上述对应宏的地方被替换。
询问:上述写法是否具有什么缺陷?
我们在初识C中简单介绍了使用宏需要注意括号问题,因此上述代码可以改进如下:
#define Add(x,y) ((x)+(y));
1、对每个参数都要添加括号;
2、对宏整体也要添加括号;
2)、宏中参数要添加括号的原因说明
举例一:我们的本意是要计算平方,可当参数不带括号时,若输入的是表达式,宏只会原封不动替换,以至得到一个错误逻辑:
#define SQUARE(x) x*xint main()
{int a = 9;int r = SQUARE(a+1);printf("%d\n", r);return 0;
}
预期:10*10=100,实际结果:9+1*9+1=19
3)、宏中整体要添加括号的原因说明
举例二:宏中函数本意是计算倍数值,但因为宏整体不带括号时,而输入的又是表达式,宏原封不动替换后得到错误结果:
#define DOUBLE(x) (x)+(x)
int main()
{int ret = 3*DOUBLE(100);printf("%d\n", ret);return 0;
}
预期:3*(100+100)=600,实际:3*100+100=400
上述两个例子正确写法如下:
#define SQUARE(x) ((x)*(x))
#define DOUBLE(x) ((x)+(x))
一个结论: 用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
2.2.3、#define替换规则介绍
在程序中扩展#define
定义符号和宏时,需要涉及几个步骤:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由
#define
定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define
定义的符号。如果是,就重复上述处理过程。
#define DOUBLE(x) (x)+(x)
#define Digit 200
int main()
{int ret = 3*DOUBLE(Digit);printf("%d\n", ret);return 0;
}
int ret = 3*DOUBLE(200);//如此类套用下,预处理时先解决标识符
int ret = 3*(200)+(200);//再解决宏
注意:
1. 宏参数和#define
定义中可以出现其他#define
定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define
定义的符号的时候,字符串常量的内容并不被搜索。
#define Digit 200
int main()
{printf("Digit 的取值是 %d\n", Digit);return 0;
}
"Digit 的取值是 %d\n"
这是字符串,故其中的Digit是不会被替换的。
2.2.4、#和##
2.2.4.1、#
1)、铺垫知识:字符串是有自动连接的特性
当两个连续字符串中间什么也没有时(此处空格可省略不加):
int main()
{char* p = "hello" " world\n";printf("hello" " world\n");printf("%s\n",p);return 0;
}
2)、问题引入
int main()
{int a = 10, b = 20, c = 30;printf("the value of a is %d\n", a);printf("the value of b is %d\n", b);printf("the value of c is %d\n", c);return 0;
}
如上,若此类语句具有很多条,是否有更高效的方法起到套用、批量的处理?
可能我们首先能想到的是自定义函数:
void print1(int n)
{printf("the value of n is %d\n", n);
}void print2(char c,int n)
{printf("the value of %c is %d\n", c,n);
}int main()
{int a = 10, b = 20, c = 30;print1(a);print1(b);print2('c',c);return 0;
}
如上述,若我们使用print1
的写法, 并不能达到效果,若使用print2
的效果,则需要多传递一个参数。
还有么有什么比较方便的解决办法?
3)、#的使用演示:
关于#
的作用:把一个宏参数变成对应的字符串。
演示一: 在我们使用宏时,若直接代入其效果和使用函数print1
类似。
#define PRINT(N) printf("the value of N is %d\n",N)
int main()
{int a = 10, b = 20, c = 30;PRINT(a);PRINT(b);PRINT(c);return 0;
}
演示二: 若加入了#
,根据其作用,可得如下结果
#define PRINT(N) printf("the value of "#N" is %d\n",N)
int main()
{int a = 10, b = 20, c = 30;PRINT(a);PRINT(b);PRINT(c);return 0;
}
对比.i
文件,可看到#
把一个宏参数变成对应的字符串的含义,即#N=="N"
,再加之之前1)中铺垫的字符串的连续性特点,可以达到完整输出一段字符的效果。且和print2
相比,少使用了一个参数。
演示三: 上述是对相同类型的使用方式,假如所给数据是不同类型,又该如何处理?
写法一:
#define PRINT(N,format) printf("the value of "#N" is "format"\n",N)
int main()
{int a = 10, b = 20;double c = 22.2, d = 33.3;PRINT(a, "%d");PRINT(b, "%d");PRINT(c, "%lf");PRINT(d, "%lf");return 0;
}
写法二:
#define PRINT(N,p) printf("the value of "#N" is %"#p"\n",N)
int main()
{int a = 10, b = 20;double c = 22.2, d = 33.3;PRINT(a,d);PRINT(b,d);PRINT(c,lf);PRINT(d,lf);return 0;
}
2.2.4.2、##
1)、##的使用演示
##
可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符。
需要注意的是,这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
代码演示如下:
#include<stdlib.h>
#include<time.h>#define STU(name, id) name##idint main()
{srand((unsigned int)time(NULL));int student1 = rand() % 40 + 60;int student2 = rand() % 40 + 60;int student3 = rand() % 40 + 60;int student4 = rand() % 40 + 60;int student5 = rand() % 40 + 60;printf("%d\n", STU(student, 1));printf("%d\n", STU(student, 2));printf("%d\n", STU(student, 3));printf("%d\n", STU(student, 4));printf("%d\n", STU(student, 5));return 0;
}
2.2.5、 带副作用的宏参数
如下述代码,输出结果是什么?
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{int a = 5;int b = 8;int c = MAX(a++, b++);printf("%d\n", c);printf("%d\n", a);printf("%d\n", b);return 0;
}
结果如图所示:
原因如下:因为MAX在此处非函数而是宏,替换后效果如下,再加之后置自增的作用,故得到上述结果。
int c = ((a++) > (b++) ? (a++) : (b++));
2.3、#undef
#undef
:这条指令用于移除一个宏定义。
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
代码演示如下:
#define MAX(x, y) ((x)>(y)?(x):(y))int main()
{int a = 5;int b = 8;int c = MAX(a++, b++);printf("%d\n", c);printf("%d\n", a);printf("%d\n", b);//……
#undef MAXint d = MAX(a, b);printf("%d\n", d);return 0;
}
2.4、命令行定义
许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。
//linux 环境演示:设INST为我们将设置的符号名
gcc -D INST=10 programe.c
演示如下:
打开vim写入这样一段C程序,可看到我们并没有定义数组大小。
[wj@VM-4-3-centos T0307]$ ls
test.c
[wj@VM-4-3-centos T0307]$ vim test.c
[wj@VM-4-3-centos T0307]$ cat -n test.c1 #include<stdio.h>2 3 int main()4 {5 int arr[sz];6 int i=0;7 for (i=0;i<sz;++i)8 {9 arr[i]=i;10 }11 for(i=0;i<sz;++i)12 {13 printf("%d ",arr[i]);14 }15 return 0;16 }
[wj@VM-4-3-centos T0307]$
现在我们来运行看看:
[wj@VM-4-3-centos T0307]$ ls
test.c[wj@VM-4-3-centos T0307]$ gcc -o test.out test.c
test.c: In function ‘main’:
test.c:5:13: error: ‘sz’ undeclared (first use in this function)int arr[sz];^
test.c:5:13: note: each undeclared identifier is reported only once for each function it appears in
[wj@VM-4-3-centos T0307]$
可看到程序报错,报错原因是sz
未定义。
此时就可以使用我们的命令行定义来修正:需要注意这步操作也是在预处理阶段完成的。
[wj@VM-4-3-centos T0307]$ gcc -o test.out test.c -Dsz=10
[wj@VM-4-3-centos T0307]$ ls
test.c test.out
[wj@VM-4-3-centos T0307]$ ./test.out
0 1 2 3 4 5 6 7 8 9
[wj@VM-4-3-centos T0307]$ gcc -o test.out test.c -D sz=100
[wj@VM-4-3-centos T0307]$ ls
test.c test.out
[wj@VM-4-3-centos T0307]$ ./test.out
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
2.5、条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃时,可以使用条件编译指令。常见的条件编译指令如下 :
2.5.1、格式一
语法格式如下:
#if 常量表达式
//...
#endif
常量表达式为真,则条件编译内的语句执行。
代码演示:
#define N 100+2int main(void)
{
#if 1printf("get you the moon.\n");
#endif#if 0printf("in the end.\n");
#endif#if Nprintf("welcome to the internet\n");
#endifreturn 0;
}
2.5.2、格式二:多个分支的条件编译
语法格式如下:
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
代码演示:
#define N 222
int main()
{
#if 1printf("A Long Way.\n");printf("Whispering Still.\n");
#elif 0printf("Goodbye.\n");printf("Wake up.\n");
#elif Nprintf("Another World.\n");
#elseprintf("Over My Head.\n");
#endifreturn 0;
}
2.5.3、判断是否被定义
语法格式如下:
写法一:
#if defined (symbol) //如果定义了symbol,则执行语句
//...
#endif#if !defined (symbol) //如果未定义symbol,则执行语句
//...
#endif
写法二:第二种写法没有括号
int main()
{
#ifdef symbol //如果定义了symbol,则执行语句
//...
#endif#ifndef symbol //如果未定义symbol,则执行语句
//...
#endifreturn 0;
}
需要注意的是,这种判断只针对是否被定义,不在意被定义的值。
以下为两种写法的代码演示:
#define N 0
int main()
{
#if defined (N)printf("normal no more.\n");
#endif#if !defined (N)printf("the sound of silence.\n");
#endifreturn 0;
}
#define N 0
int main()
{
#ifdef Nprintf("normal no more.\n");
#endif#ifndef Nprintf("the sound of silence.\n");
#endifreturn 0;
}
2.5.4、嵌套指令
效果如下:
#if defined(OS_UNIX)#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif
#endif
此类定义在库中常见:
2.6、文件包含
2.6.1、头文件包含的方式
2.6.1.1、本地文件包含
1)、基础说明
相关格式如下:本地头文件,包含时需要使用引号
#include "filename"
查找策略:①编译器先在源文件所在目录下查找。②如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。③如果找不到就提示编译错误。
如下图,就是本地源文件所在路径,若找不到则去对应的库函数所在文件路径下寻找。
#include"test.h"
int mian()
{return 0;
}
2)、Linux下库函数路径
相关路径:
/usr/include
2.6.1.2、库文件包含
1)、基础说明
相关格式如下:对于库函数,其头文件可以直接去标准路径下去查找,如果找不到就提示编译错误。
#include <filename.h>
问题:对于库函数头文件,是否可以使用“”
的形式包含?
回答:可以。但从效率角度讲,这样子效率相对角度。
2.6.2、嵌套包含
2.6.2.1、相关现象
1)、现象演示
#include
包含的头文件,会在我们的.源文件中展开。预处理器先删除这条指令,并用包含文件的内容替换。那么假设这样一个源文件中包含该头文件N次,那就实际也被编译了N次。
如图所示:
相关代码:
2 int add(int x,int y)3 {4 return x+y;5 }
~
1 #include<stdio.h>2 3 #include"test.h" 4 #include"test.h"5 #include"test.h"6 int main()7 {8 int a=10;9 int b=20;10 printf("%d\n",add(a,b));11 return 0;12 }
~
835 # 943 "/usr/include/stdio.h" 3 4
836
837 # 2 "test.c" 2
838
839 # 1 "test.h" 1
840
841 int add(int x,int y)
842 {
843 return x+y;
844 }
845 # 4 "test.c" 2
846 # 1 "test.h" 1
847
848 int add(int x,int y)
849 {
850 return x+y;
851 }
852 # 5 "test.c" 2
853 # 1 "test.h" 1
854
855 int add(int x,int y)
856 {
857 return x+y;
858 }
859 # 6 "test.c" 2
860 int main()
861 {
862 int a=10;
863 int b=20;
864 printf("%d\n",add(a,b));
865 return 0;
866 }
2.6.2.2、解决方案一
2)、如何解决?
方法一:
相关格式如下:
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
//这里的__TEST_H__是根据你的头文件来改变的,假如叫mylist.h,则为__MYLIST_H__
实际运用如下:
相关代码如下:
1 #ifndef __TEST_H__2 #define __TEST_H__ 3 int add(int x,int y)4 {5 return x+y;6 }7 #endif8
835 # 943 "/usr/include/stdio.h" 3 4
836
837 # 2 "test.c" 2
838
839 # 1 "test.h" 1
840
841
842 int add(int x,int y)
843 {
844 return x+y;
845 }
846 # 4 "test.c" 2
847
848
849 int main()
850 {
851 int a=10;
852 int b=20;
853 printf("%d\n",add(a,b));
854 return 0;
855 }
2.6.2.3、解决方案二
方法二:
相关格式如下:
#pragma once
实际运用如下:
相关代码如下:
9 #pragma once 10 int add(int x,int y)11 {12 return x+y;13 }
相关文章:
【ONE·C || 程序编译简述】
总言 C语言:程序编译相关。 文章目录总言1、程序的翻译环境和运行环境1.1、简述1.2、翻译环境:程序编译与链接1.2.1、简介:程序如何从.c文件形成.exe可执行程序1.2.2、过程说明1.3、运行环境2、预处理详解2.1、预定义符号2.2、#define2.…...
MGAT: Multimodal Graph Attention Network for Recommendation
模型总览如下: 图1:多模态图注意力网络背景:本论文是对MMGCN(Wei et al., 2019)的改进。MMGCN简单地在并行交互图上使用GNN,平等地对待从所有邻居传播的信息,无法自适应地捕获用户偏好。 MMGCN…...
在SNAP中用sentinel-1数据做InSAR测量,以门源地震为例
在SNAP中用sentinel-1数据做InSAR0 写在前面1 数据下载2 处理步骤2.1 split2.2 apply orbit 导入精密轨道2.3 查看数据的时空基线base line2.4 back-geocoding 配准2.5 Enhanced Spectral Diversity2.6 Deburst2.7 Interogram Formation 生成干涉图2.8 Multilook 多视2.9 Golds…...
MySQL常用函数
什么是函数? 函数是指一段可以直接被另一段程序调用的程序或代码。 字符串函数 函数功能CONCAT(S1,S2,…Sn)字符串拼接,将S1,S2,… Sn拼接成一个字符串LOWER(str)将字符串str全部转为小写LOWER(str)将字符串str全部转为小写LPAD(…...
51单片机数字电子钟开题报告
目录 选题背景 初步设计方案 芯片的选型 编译环境 关键问题 策略 方案 参考文献 选题背景 数字电子钟是一种受到越来越多人喜爱的钟表,其准确性和稳定性成为设计和研发的重要考虑因素。在现代社会,时间的准确性对于各行各业都非常重要࿰…...
day7 HTTP协议
HTTP协议 什么是协议? 协议实际上是某些人,或者某些组织提前制定好的一套规范,大家都按照这个规范来,这样可以做到沟通无障碍。协议就是一套规范,就是一套标准。由其他人或其他组织来负责制定的。我说的话你能听懂&…...
3DCAT+一汽奥迪:共建线上个性化订车实时云渲染方案
近年来,随着5G网络和云计算技术的不断发展,交互式3D实时云看车正在成为一种新的看车方式。与传统的到4S店实地考察不同,消费者可以足不出户,通过网络与终端设备即可实现全方位展示、自选汽车配色、模拟效果、快捷选车并进行个性化…...
yii2项目使用frp https2http插件问题
yii2内网项目,使用frp进行内网穿透,使用 https2http插件把内网服务器http流量转成https,会存在一个问题:当使用 $this->redirect(...) 或 $this->goHome() (其实用的也是前者)等重定向时,…...
关于 interface{} 会有啥注意事项?下
我们一起来回顾一下上一次说到的 interface{} 可以用来做多态 接口类型分为空接口类型和非空接口类型,他们的底层数据结构不太一样 这里顺便说一下,用来作态需要满足这样的条件: 首先得有父类指针指向子类的对象这个接口还必须是非空接口…...
ansible组件介绍和简单playbook测试
一、ansible inventory 在大规模的配置管理工作中,管理不同业务的机器,机器的信息都存放在ansible的inventory组件里面。在工作中,配置部署针对的主机必须先存放在Inventory里面,然后ansible才能对它进行操作。默认的Ansible的in…...
[数据结构]:13-插入排序(顺序表指针实现形式)(C语言实现)
目录 前言 已完成内容 插入排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为C语言代…...
es6 new Promise
Promise 是一个构造函数,本身身上有 all、reject、resolve 这几个方法,原型上有 then、catch 等方法。所以 Promise new 出来的对象确定就有 then、catch 方法。Promise 的构造函数接收一个参数,是函数,而且传入两个参数ÿ…...
Python爬虫实战:使用Requests和BeautifulSoup爬取网页内容
标题:Python爬虫实战:使用Requests和BeautifulSoup爬取网页内容 Python爬虫技术是网络爬虫中的一种,它可以从互联网上抓取各种网页信息,如文本、图片、视频等,并将它们存储在本地数据库中。Python语言具有简单易学、语…...
质量指标——什么是增量覆盖率?它有啥用途?
目录 引言 什么是增量覆盖率 增量覆盖率有啥用途 1、对不同角色同学的用途 2、对不同规模的业务需求的用途 增量覆盖率的适用人员 增量覆盖率不太适用的情况 引言 有些质量团队,有时会拿「增量覆盖率」做出测试的准出卡点。 但在实际的使用过程中,…...
Hive---拉链表
拉链表 文章目录拉链表定义用途案例全量流程增量流程合并过程第一步第二步第三步案例二(含分区)创建外部表orders增量分区表历史记录表定义 拉链表是一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的,顾名思义&am…...
日常文档标题级别规范
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…...
C++学习记录——십이 vector
文章目录1、vector介绍和使用2、vector模拟实现insert和erase和迭代器失效补齐其他函数深浅拷贝难点思考1、vector介绍和使用 vector可以管理任意类型的数组,是一个表示可变大小数组的序列容器。 通过vector文档来看它的使用。 #include <iostream> #inclu…...
Lombok常见用法总结
目录一、下载和安装二、常见注释(一)Data(二)Getter和Setter(三)NonNull和NotNull(不常用)(四)ToString(不常用)(五&#…...
【Ajax】异步通信
一.概述 概念:AJAX(Asynchronous JavaScript And XML):异步的 JavaScript 和 XML 作用: 与服务器进行数据交换:通过AJAX可以给服务器发送请求,并获取服务器响应的数据 使用了AJAX和服务器进行通信,就可以使…...
近红外吸收荧光染料IR-808,IR-808 NH2,IR-808 amine,发射808nm 性质分享
中文名称:IR-808 氨基英文名称:IR-808 NH2,IR-808 amine,IR-808-NH2规格标准:10mg,25mg,50mgCAS:N/A产品描述:IR-808,发射808nm,酯溶性染料修饰氨…...
一图来看你需要拥有那些知识储备
技术实践 数据 关系型数据 MySQLSQLServerOraclePostgrSQLDB2 大数据存储 RedisMemcacheMongoDBHBaseHive 大数据处理 Hadoop 数据报表看板 DataGearGrafanaKibanaMetaBase 消息对列 Rabbit MQRock MQActive MQKafka 大数据搜索 SolrElasticSearchLucenHive 服务提…...
复位和时钟控制(RCC)
目录 复位 系统复位 电源复位 备份区复位 时钟控制 什么是时钟? 时钟来源 二级时钟源: 如何使用CubeMX配置时钟 复位 系统复位 当发生以下任一事件时,产生一个系统复位:1. NRST引脚上的低电平(外部复位) 2. 窗口看门狗计数终止(WWD…...
OpenWrt 专栏介绍00
文章目录OpenWrt 专栏介绍00专栏章节介绍关于联系方式OpenWrt 专栏介绍00 专栏章节介绍 本专栏主要从开发者角度,一步步深入理解OpenWrt开发流程,本专栏包含以下章节,内如如下: 01.OperWrt 环境搭建02.OperWrt 包管理系统03.Op…...
udk开发-稀里糊涂
一、EDK2简介 1.EDK2工作流 二、EDK2 Packages 1.Packages介绍 EDK2 Packages是一个容器,其中包含一组模块及模块的相关定义。每个Package是一个EDK2单元。 整个Project的源代码可以被分割成不同的Pkg。这样的设计不仅可以降低耦合性,还有利于分…...
Java之内部类
目录 一.内部类 1.什么是内部类 2.内部类存在的原因 3. 内部类的分类 4.内部类的作用 二.成员内部类 1.基本概念 2.成员内部类的注意点 1.成员内部类可以用private方法进行修饰 2.成员内部类可以直接访问外部类的私有属性 3.外部类可以通过对象访问内部类的私有属性 …...
【MyBatis】篇二.MyBatis查询与特殊SQL
文章目录1、MyBatis获取参数值case1-单个字面量类型的参数case2-多个字面量类型的参数case3-map集合类型的参数case4-实体类类型的参数case5-使用Param注解命名参数总结2、MyBatis的各种查询功能case1-查询结果是一个实体类对象case2-查询结果是一个List集合case3-查询单个数据…...
CE认证机构和CE证书的分类
目前,CE认证已普遍被应用在很多行业的商品中,也是企业商品进入欧洲市场的必备安全合格认证。在船舶海工行业中,也同样普遍应用,很多时候,对于规范中没有明确认证要求的设备或材料,而船舶将来还会去欧洲水域…...
Lesson 8.2 CART 分类树的建模流程与 sklearn 评估器参数详解
文章目录一、CART 决策树的分类流程1. CART 树的基本生长过程1.1 规则评估指标选取与设置1.2 决策树备选规则创建方法1.3 挑选最佳分类规则划分数据集1.4 决策树的生长过程2. CART 树的剪枝二、CART 分类树的 Scikit-Learn 快速实现方法与评估器参数详解1. CART 分类树的 sklea…...
【Unity】程序集Assembly模块化开发
笔者按:使用Unity版本为2021.3LTS,与其他版本或有异同。请仅做参考 一、简述。 本文是笔者在学习使用Unity引擎的过程中,产学研的一个笔记。由笔者根据官方文档Unity User Manual 2021.3 (LTS)/脚本/Unity 架构/脚本编译/程序集定义相关部分结…...
马尔可夫决策过程
1. 马尔可夫决策过程 马尔可夫决策过程不过是引入"决策"的马氏过程. Pij(a)P{Xn1j∣X0,a0,X1,a1,...,Xni,an1}P{Xnn1j∣Xni,ana}\begin{split} P_{ij}(a) & P\{X_{n1} j|X_0, a_0, X_1, a_1, ..., X_n i, a_n 1\} \\ &P\{X_n{n1} j|X_n i, a_n a\} \e…...
广州城乡建设网站/昆明seo技术培训
当地时间3月19日,IBM Qiskit正式发布了Qiskit Metal[1],一款用于超导量子计算机的开源电子设计自动化(EDA)软件。官方表示很期待看到Qiskit Metal在这个领域即将产生的影响,毕竟,IBM Qiskit已经从早期体验者…...
对于网站建设提出建议/链接买卖平台
论文:https://openreview.net/forum?id_WnAQKse_uK 代码:https://github.com/Annbless/ViTAE 1、Motivation 这个论文的思想非常简单:将CNN和 VIT 结合,浅层用CNN,深层用VIT。 同时,在attention 分支添加…...
做微信封面的网站/怎么创建网站链接
介绍jwt 1、JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github.com/jwtk/jjwt 2、什么是jwt Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的࿰…...
网站怎么申请备案/湖南平台网站建设设计
是的,这是可能的。有用于这些目的的模块,称为MSG PY。例如:from independentsoft.msg import Messagefrom independentsoft.msg import Recipientfrom independentsoft.msg import ObjectTypefrom independentsoft.msg import DisplayTypefro…...
joomla 网站建设教程/代运营公司哪家好一些
11.25事物隔离级别事物日志redo undo事物锁 begin; update事物日志性能优化 innodb_flush_log_at_trx_commit0|1|2|3innodb事务日志相关配置; show variables like %innodb_log%;通用日志通用日志:记录对数据库的通用操作,包括错误的SQL语句通…...
做外贸有哪些网站/站长工具平台
惠州正规的冰箱面板联系方式,环宇新型材料,佛山市环宇新型材料有限公司成立于2010年2月,公司座落于交通便利、位置优越、环境优美的广东省佛山市三水区西南工业园C区。惠州正规的冰箱面板联系方式, PCM冰箱面板、PVC冰箱面板、VCM…...