手机网站怎么布局/百度免费注册
文章目录
- 0. 前言
- 1. 程序的翻译环境和执行环境
- 2. 被隐藏的过程
- 2.1 翻译环境
- 2.2 编译
- 3.2.1 预编译
- 3.2.2 编译
- 2.2.3 汇编
- 2.3 链接
- 2.4 运行环境
- 3. 预处理
- 3.1 预定义符号
- 3.2 #define
- 3.2.1 #define定义标识符
- 3.2.2 #define定义宏
- 3.2.3 #define替换规则
- 3.2.4 #和##
- 3.2.5 带副作用的宏参数
- 3.2.6 宏和函数对比
- 3.2.7 命名约定
- 3.3 undef
- 3.4 命令行定义
- 3.5 条件编译
- 3.6 文件包含
- 3.6.1 头文件被包含的方式
- 3.6.2 嵌套文件包含
- 4. 结语
0. 前言
现在的我们写代码大多数用的集成开发环境(IDE),比如Visual Studio、Idea等,这样的IDE一般都将编译和链接的过程一步完成。一句简简单单的Hello World,在我们看来,这一步到位,小菜一碟。可是一句话说的好不是岁月静好,只是有人在替你负重前行。这里面一些复杂的过程,集成工具已经默默的处理掉了。可是当我们写的程序出了一些莫名其妙的错误,让我们头大且掉发,我们只能看到这些问题的表象,难以看清本质,这些问题的本质就是软件运行背后的机理及支撑软件运行的各种平台和工具,如果能够了解这些机制,那么对待这些问题,就会有新的看法。
1. 程序的翻译环境和执行环境
在ANSI C存在两个不同的环境:
- 翻译环境,在这个环境中源代码被转换为可执行的机器指令。
- 执行环境,实际用于执行代码。
我们知道,计算机只能执行二进制指令,但我们一般写的代码,都不是以二进制形式写,以C语言为例:
#include<stdio.h>
int main()
{printf("C 语言\n");return 0;
}
这段C语言代码,如果要执行,那么就需要翻译环境将其翻译为二进制指令。我们所使用的一些编译器,就充当着"翻译官"的角色。当然了将我们的源代码,转换成可执行程序,这个翻译的过程能细分为2个步骤编译和链接。
2. 被隐藏的过程
2.1 翻译环境
组成一个程序的每个源文件通过编译过程转换成目标代码。
每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且也可以搜索到我们自己写的函数,将需要的函数也链接到程序中。
2.2 编译
编译可细分为三个小的过程:
3.2.1 预编译
首先是源代码文件和相关的头文件,被编译成一个 .i 文件。对于C程序来说,它的源文件拓展名是 .c,头文件拓展名是 .h ,而预编译后的文件拓展名是 .i 。
预编译命令(-E表示只进行预编译):
$ gcc -E test.c -o test.i
预编译过程主要处理那些源代码文件中的以 **#**开始的预编译指令。主要处理规则如下:
- 将所有的 #define 删除,并且展开所有的宏定义。
- 处理 #include 预编译指令,将被包含的文件插入到该预编译指令的位置。
- 删除所有的注释 // 和 / ** /。
- 添加行号和文件标识,比如 #7 “test.h” 2,以便于编译时编译器产生调试用的行号信息及用于产生编译错误或警告时能产生行号。
- 报了所有的 #pragma 编译器指令,因为编译器要使用他们。
经过预编译后,.i 文件不包含任何宏定义,因为所有的宏定义已经被展开,并且包含的文件也已经被插入到 .i 。所以无法判断宏定义和头文件是否包含正确,那么接下来就是通过查看编译后的文件进行判断。
3.2.2 编译
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析、符号汇总及优化后产生相应的汇编代码文件,这是这个程序构建的核心部分。
编译命令:
$ gcc -S test.i
2.2.3 汇编
汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。所以汇编器的汇编过程相当于编译器来讲比较简单,它没有复杂的语法,也不用做优化指令,只根据汇编指令和机器指令的对照表一一翻译就可以了。原来汇编才是一个血统纯正的“翻译官”啊,不带任何“感情色彩”。
汇编命令:
$ gcc -c test.s
汇编完成后输出目标文件、将汇编代码翻译成二进制代码(存放到目标文件中),同时形成符号表。
2.3 链接
现在软件开发过程中,软件的规模往往都很大,动辄数百万行的代码,如果将这些代码全部都放在一个模块肯定无法想象。所以我们一般在写代码的时候,会分模块,这些模块之间相互依赖又相互独立。
那么链接就能将这些模块拼接起来,最后产生一个可执行的程序。
2.4 运行环境
程序执行的过程:
- 程序必须载入到内存中。在有操作系统的环境中,这个一般由操作系统来完成。在独立的环境中,程序的载入必须手工来安排,也可能是通过可执行代码置入只读内存来完成。
- 程序的执行便开始,接着便调用main函数。
- 开始执行程序代码。这时候程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储于静态内存中的变量会一直保留。
- 终止程序。正常终止main函数,也可能意外终止,程序挂掉了。
3. 预处理
3.1 预定义符号
int main()
{printf("%s\n", __FILE__);//进行编译的源文件的路径printf("%d\n", __LINE__);//文件当前行号printf("%s\n", __DATE__);//文件被编译的日期printf("%s\n", __TIME__);//文件被编译的时间//VS2022不支持printf("%s\n", __STDC__);//如果编译器遵循ANSI C,其值为1,否则未定义return 0;
}
通过gcc编译器可以发现,这些确实是在预编译阶段,就完成了替换
3.2 #define
3.2.1 #define定义标识符
语法:
#define name stuff
代码示例:
#define MAX 100
#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__ )
那么,我们在定义 #define 的时候后面是否要加上 ; 呢?
通过前面的预编译知识,#define 的内容将会被替换,加上 ; 会造成不必要的麻烦。
比如下面的场景:
#define MAX 100;
int main()
{int m = 0;if (m >= 0)m = MAX;elsem = -1;return 0;
}
我们通过gcc编译器可以看到在预编译阶段,100 后面的 ==;==也被添加上去了,导致else匹配不到if语句。
3.2.2 #define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种通常称为宏或者定义宏。
宏的声明方式:
#define name( parament-list ) stuff
注意:
- 其中的partment-list是一个逗号隔开的符号表,它可能出现在sturff中。
- 参数列表的左括号必须与name紧邻。
- 如果两者之间有任何空白存在,参数列表就会解释为stuff的一部分。
代码示例:
#define SQUARE(X) X*X //求一个数的平方
int main()
{printf("%d\n", SQUARE(5));printf("%lf\n", SQUARE(5.0));return 0;
}
但是呢,这段代码还存在一定的风险,如果在宏里面输入的是 (5+1),那么就会被替换成 5 + 1 * 5 + 1,这样输出的值就和我们原本的意愿不符合。
这里,我们在宏定义上加括号,就能很好的解决问题。
代码示例:
#define SQUARE(X) (X)*(X) //求一个数的平方
int main()
{printf("%d\n", SQUARE(5+1));return 0;
}
//输出 36
那这样就真的避免了风险吗?当然,避免了刚才出的问题,但是又产生了新的问题。
代码示例:
#define DOUBLE(X) (X)+(X) //求一个数的平方
int main()
{printf("%d\n", 10*DOUBLE(5));return 0;
}
//输出 55
我们原意是 10 * (5 + 5),可是这里替换成了 10 * 5 + 5,又违背了我们的意愿。
这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。
#define DOUBLE(X) ((X)+(X)) //求一个数的平方
int main()
{printf("%d\n", 10 * DOUBLE(5));return 0;
}
//输出 100
小贴士:
- 以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
3.2.3 #define替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
- 在调用宏时,首先对参数进行检查,看看是否包含由 #define 定义的符号。如果是,它们首先被替换。
- 替换后的文本随后被插入到程序原来的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看是否包含由 #define 定义的符号。如果是,重复上述过程。
注意:
1.宏参数和 #define 定义中可以出现其他 #define 定义的符号。但是对于宏,不能出现递归。
2.当预处理器搜索 #define 定义的符号的时候,字符串常量的内容并不被搜索。
3.2.4 #和##
我们先来看这段代码:
int main()
{printf("hello world\n");printf("hello " "world\n");return 0;
}
这两句printf输出的内容其实都是一样的hello world,那我们就能得出结论:字符串是有自动连接特点的。
有这个结论后,我们就可以这样写代码:
#define PRINT(format,x) printf("the value of "#x" is "format"\n",x)
int main()
{int a = 10;PRINT("%d", a);float b = 1.5;PRINT("%f", b);return 0;
}
这里 # 的作用就是把一个宏参数变成对于的字符串。
##的作用
##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。
注:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
代码示例:
#define CAT(x,y) x##y
// RMB##100
// RMB100
int main()
{int RMB100 = 20;printf("%d", CAT(RMB, 100));return 0;
}
3.2.5 带副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
例如:
int main()
{int a = 1;int b = a + 1;//无副作用int c = ++a; //有副作用return 0;
}
同理,下面这段代码就能充分证明宏参数所引起的副作用
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{//printf("%d\n", MAX(2, 3));int a = 4;int b = 5;int m = MAX(a++, b++);//预处理之后//int m = ((a++)>(b++)?(a++):(b++));// 5 6 7printf("%d\n", m);printf("a = %d b = %d\n", a,b);//5 7return 0;
}
3.2.6 宏和函数对比
宏通常用于执行简单的运算(两数中求大值)。
那用函数求,和这个有什么区别呢?
- 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于来比较的类型。
宏是类型无关的。
当然了,现在写代码时,大部分还是写函数,很少写宏。
宏的缺点:
- 宏定义是插入代码中,除非宏比较短,否则将大幅度增大程序的长度。
- 宏在预处理就替换了,无法调试发现问题。
- 宏与类型无关,自然也就不够严谨(双刃剑)。
- 宏会带来运算符优先级的问题,容易导致出错。
宏和函数的一个对比:
属性 | #define宏定义 | 函数 |
---|---|---|
代码长度 | 每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,所以相对慢一些 |
操作符优先级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测 |
带有副作用的参数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果 | 函数参数只在传参的时候求值一次,结果更容易控制 |
参数类型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型 | 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是相同的 |
调试 | 宏不方便调试 | 函数可以逐语句调试 |
递归 | 宏不能递归 | 函数可以递归 |
3.2.7 命名约定
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写
3.3 undef
用于移除宏定义
#define NAME RMB
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
3.4 命令行定义
许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。
例如:当我们根据同一个源文件要编译出一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大些,我们需要一个数组能够大些。)
#include <stdio.h>
int main()
{int array [SZ];int i = 0;for(i = 0; i< SZ; i ++){array[i] = i;}for(i = 0; i< SZ; i ++){printf("%d " ,array[i]);}printf("\n" );return 0;
}
这里用gcc以命令行的形式操作,可以观察到,SZ通过命令行定义,发生了替换。
3.5 条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
比如说:
调试性的代码,删除可惜,保留碍事,那么我们可以选择性的编译
代码示例:
#define _DEBUG_ 1
int main()
{
#ifdef _DEBUG_printf("1\n");
#endif#ifdef DEBUG //未定义,所以不会编译printf("0\n");
#endifreturn 0;
}
常见的条件编译指令:
1.
#if 常量表达式//...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__//..
#endif
2.多个分支的条件编译
#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
3.6 文件包含
在C语言写的大大大部分的代码中,我们都会用到 #include 这条指令,这条指令可以使另一个文件被编译。
3.6.1 头文件被包含的方式
本地文件被包含:
#include "filename"
查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。
如果找不到就提示编译错误。
库文件包含:
#include <filename.h>
那这样来说,是不是包含库文件,就直接用 ==" "==包含不久行了吗?
理论可行,但是不切实际。
3.6.2 嵌套文件包含
当项目十分庞大或者我们不小心多次包含同一个文件时:
这样会造成文件的内容重复,那么我们可以通过条件编译来解决这个问题。
#ifndef _TEST_H_
#define _TEST_H_
//头文件的内容
#endif //_TEST_H_
这样写可能会有些麻烦,写成下面这种形式就简单很多:
//在VS2022中,创建本地头文件,编译器会自动加上
#pragma once
4. 结语
本篇文章参考《程序员的自我修养——链接、装载与库》的第一章内容,之后也会慢慢更新从书本中学到的知识。本周上课听老师讲,计算机的一些专业名称的含义。
比如:计算机科学与技术,科学是摆在技术前面的,扎实的理论基础,更利于我们技术的提升,所以在有一定技术基础的前提下,可尝试学习部分理论,这样会让我们的水平再往上升。
相关文章:

被隐藏的过程——预处理
文章目录0. 前言1. 程序的翻译环境和执行环境2. 被隐藏的过程2.1 翻译环境2.2 编译3.2.1 预编译3.2.2 编译2.2.3 汇编2.3 链接2.4 运行环境3. 预处理3.1 预定义符号3.2 #define3.2.1 #define定义标识符3.2.2 #define定义宏3.2.3 #define替换规则3.2.4 #和##3.2.5 带副作用的宏参…...

strace 用法介绍
strace 是什么 strace 是一个可用于诊断和调试的 Linux 用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。 strace 作为一种动态跟踪工具,能够帮助我们高效地定位进程和服务故障。它像是一个侦探&…...

TiDB数据库架构概述
文章目录TiDB体系架构TiDB ServerStorage Cluster(存储引擎)PD cluster题目TiDB体系架构 TiDB Server Sql语句最先到达 TiDB Server集群 它是无状态的,数据并不是存储在这里面,当一个会话连接到TiDB Server集群上,sql语句发过来,…...

[深入理解SSD系列综述 闪存实战2.1.2] SLC、MLC、TLC、QLC、PLC NAND_固态硬盘闪存颗粒类型
闪存最小物理单位是 Cell, 一个Cell 是一个晶体管。 闪存是通过晶体管储存电子来表示信息的。在晶体管上加入了浮动栅贮存电子。数据是0或1取决于在硅底板上形成的浮动栅中是否有电子。有电子为0,无电子为1. SSD 根据闪存颗粒区分,固态硬盘有SLC、MLC、TLC、QLC、PLC 五种类型…...

游戏逆向之游戏技能分析
角色的当前技能列表往往都是从系统的技能库中进行筛选而组成的,而这个筛选的过程大多非常的复杂,经过的代码和临时结构体的传递也非常的多,所以在分析技能对象来源的时候常常要将OD和CE配合来使用。下面我们来分析下《天堂2》的技能列表。 首…...

汽车制造商与IT公司之间的技术合作案例
如果您对最新汽车技术感兴趣的话,您可能经常听到汽车制造商和IT公司正在合作开发技术的消息。汽车生产商为何自身不进行技术开发,而是与IT企业合作呢?因为最近随着以IT技术为基础的电动汽车等环保汽车或无人驾驶汽车等的登场和发展,汽车制造商单独进行技术开发需要花费很多时间…...

funkyheatmap | 用这个包来完美复刻Nature Biotechnology的高颜值神图吧!~
1写在前面 天气开始暖和了☀️,发现旅游的人好多啊!~🥲 不知道自己什么时候能有时间出去看看外面的世界,实在是太忙了。😷 最近用到的有个包感觉很不错,分享给大家,funkyheatmap包。ὡ…...

tomcat8调优
环境说明Jdk:1.8Tomcat: 8.5.69服务器 :2核 8G方案当调整Tomcat配置时,具体的配置方法可能会有所不同,因为它们受到许多因素的影响,例如Tomcat版本、操作系统、硬件配置等等。以下是每个建议的一些具体配置示例&#x…...

VS Code 解决 SpringBoot 项目启动时报 Failed to refresh live data from process **** 的问题
问题 SpringBoot 启动后 ,VS Code 报错 Failed to refresh live data from process ****。 现场是,SpringBoot 项目启动时,VS Code 将进行如下刷新,图片如下所示 当刷新 10 次以后,如果还是失败,则会抛出…...

[ 红队知识库 ] 各种重要文件路径
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...

Ajax和JSON的基本用法
局部请求页面不会变化,返回的响应我们要动态获取,获取后选择数据更新区域。<body> <input id"btnLoad" type"button" value"加载"> <div id"divContent"></div> <script>//获取点…...

【项目实战】基于netty-websocket-spring-boot-starter实现WebSocket服务器长链接处理
一、背景 项目中需要建立客户端与服务端之间的长链接,首先就考虑用WebSocket,再来SpringBoot原来整合WebSocket方式并不高效,因此找到了netty-websocket-spring-boot-starter 这款脚手架,它能让我们在SpringBoot中使用Netty来开发…...

BC双驱、ChatGPT大火,AI独角兽撬开盈利大门?
配图来自Canva可画 放眼AI行业,各大AI玩家长期亏损、“钱”景堪忧。 回看过去一年,部分AI独角兽的亏损问题愈发尖锐——云从科技2022年净亏损同比扩大至8.5亿元;寒武纪2022年净亏损11.6亿元,较上年同期扩大41.4%;地平…...

1/4车、1/2车、整车悬架H2/H∞控制仿真合集
目录 前言 1. 1/4悬架系统 1.1数学模型 1.2 H2/H∞求解反馈阵阵 1.3仿真分析 2. 1/2悬架系统 2.1数学模型 2.2 H2/H∞求解反馈阵阵 2.3仿真分析 3. 整车悬架系统 3.1数学模型 整车7自由度主动悬架数学模型 3.2 H2/H∞求解反馈阵阵 3.3仿真分析 4.总结 参考文献 …...

Git使用教程、命令
Git使用教程、命令 基本配置 git的配置文件位置: win: c:\users\<userName>\.gitconfig linux: /home/<userName>/.gitconfig # 个人/etc/gitconfig # 系统全局# 修改git init时的默认分支为master&#x…...

《c++ primer笔记》第九章 顺序容器
前言 知识点很多,这里只记录遗忘的。从这章开始会对前面章节的内容进行一个扩充,如果以前的忘了读起来会有点吃力。总的来说,本章节难度不大。 文章目录一、概述二、容器库概览2.1容器定义和初始化2.2赋值三、顺序容器操作3.1添加元素3.2删除…...

QML动画(弹动和翻转效果)
Flickable(弹动) QML中提供了一个Flickable元素,可以将其子项设置在一个可以拖拽和弹动的界面上,使得子项目的视图可以滚动。在传统的用户界面中,可以使用标准控件(如滚动条和箭头按钮)滚动视图…...

GPS启动方式、定位速度、定位精度介绍
前面文章介绍了GPS定位基础知识 GPS定位知识介绍 (qq.com) 本文主要介绍GPS启动方式。 定位过程中最重要的辅助信息是时间、星历、位置。 根据辅助信息不同,...

深度学习零基础学习之路——第五章 个人数据集的制作
Python深度学习入门 第一章 Python深度学习入门之环境软件配置 第二章 Python深度学习入门之数据处理Dataset的使用 第三章 数据可视化TensorBoard和TochVision的使用 第四章 UNet-Family中Unet、Unet和Unet3的简介 第五章 个人数据集的制作 深度学习数据集的制作Python深度学…...

女神节 | PHP和Java算什么,女工程师才是最美最好的语言!
世界上第一个程序员是女性 第一个发现Bug的也是女性 在智领云有一群追求快乐和独立的女性工程师 她们多有魅力? 工位上她们专注于数据与代码 平日里郊游、瑜伽、插花、科学养娃一件不落 不仅用0和1编织数字世界 也在用心装点自己的生活 今天是国际劳动妇女节…...

【Python】装饰器
一、装饰器的作用 装饰器能够为已经存在的对象添加额外的功能。 二、什么是装饰器 装饰器本质是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。 三、装饰器的应用场景 插入日志、性能…...

Spring事务及传播机制
概念 在MySQL中介绍过,当同一时间出现一起读写数据的情况,可能会导致最终的结果出错,因此可以使用事务来提高隔离级别 而Spring中也可以实现事务 手动添加事务 使用SpringBoot中的DataSourceTransactionManager对象可以获取事务࿰…...

43-Golang中的goroutine!!!
Golang中的goroutine进程和线程说明并发和并行并发并行Go协程和Go主线程案例小结goroutine的调度机制MPG模式基本介绍MPG模式运行的状态1MPG模式运行的状态2设置GOlang运行的CPU数不同 goroutine之间如何通讯使用全局变量加锁同步改进程序进程和线程说明 1.进程就是程序在操作…...

[深入理解SSD系列 闪存实战2.1.5] NAND FLASH基本读操作及原理_NAND FLASH Read Operation源码实现
前言 上面是我使用的NAND FLASH的硬件原理图,面对这些引脚,很难明白他们是什么含义, 下面先来个热身: 问1. 原理图上NAND FLASH只有数据线,怎么传输地址? 答1.在DATA0~DATA7上既传输数据,又传输地址 当ALE为高电平时传输的是地址, 问2. 从NAND FLASH芯片手册可知,要…...

pandas库中的read_csv函数读取数据时候的路径问题详解(ValueError: embedded null character)
read_csv()函数不仅是R语言中的一个读取csv文件的函数,也是pandas库中的一个函数。pandas是一个用于数据分析和处理的python库。它的read_csv函数可以读取csv文件里的数据,并将其转化为pandas里面的DataFrame对象。它由很多参数可以设置,例如…...

【量化交易笔记】4.移动平均值的实现
上一讲已经讲A股的数据下载到本地或保存数据库,我们可以随时使用。 移动平均MA(Moving Average) ,是用统计分析的方法,将一定时期内的证券价格(指数)加以平均,并把不同时间的平均值连接起来,形成…...

2023年3月份的野兔在线工具系统版本更新
这个是野兔在线工具系统中文版更新,这次更新的功能,和修改的问题还是比较多的,也修复系统部分功能,应该也是目前市面上在线工具比较多的一个系统了。系统名称:野兔在线工具系统系统语言:中文版系统源码&…...

科技成果赋智中小企业深度行 边界无限靖云甲ADR入选十大优秀案例
近日,国家工业信息安全发展研究中心、青岛市工业和信息化局、青岛市民营经济发展局、青岛市即墨区人民政府、青岛蓝谷管理局联合举办的科技成果赋智中小企业“深度行”活动(青岛站)成功举办,同步举行了赋智“深度行”活动…...

我们的理性何处安放
每天工作压力和各种人相处都让我们非常忙碌,我们上大学,努力工作,都是想获得更好的人生场景,素养,提升自身的认知,这样就是对我们大多数人生最负责任。如何让自己理性与人为善,并能被人温柔以待…...

RecyclerView的详细使用
首先就是了解ListView和RecyclerView的区别1.ListView相比RecycleView的优点a.ListView实现添加HeaderView和FooderView有直接的方法b.分割线可以直接设置c.ListView实现onItemClickListence和onItemLongClickListence有直接的方法2.RecyclerView相比ListView的优点a.封装了Vie…...