CSAPP的Lab学习——Archlab(Architecture Lab)

news2024/11/17 10:58:57

文章目录

  • 前言
  • 一、A部分
    • sum .ys:迭代求和链表元素写一个Y86-64的程序和。
    • rsum .递归求和链表元素
    • copy.ys 复制将源块复制到目标块
  • 二、B部分
  • 三、C部分
    • 实现iaddq指令
  • 总结


前言

一个本硕双非的小菜鸡,备战24年秋招。刚刚看完CSAPP,真是一本神书啊!遂尝试将它的Lab实现,并记录期间心酸历程。
代码下载

官方网站:CSAPP官方网站
这道题下载完了记得不是完事了,还有一句话需要执行

unix> cd sim
unix> make clean; make

如果执行make clean; make出现了报错,如:
在这里插入图片描述
可参考这位大佬的解决方案:林夕丶

以下是官方文档翻译:
在这个实验室中,您将学习流水线Y86-64处理器的设计和实现,优化它和基准程序以最大化性能。允许您对基准测试程序进行任何语义保留转换,或者对流水线处理器进行增强,或者两者都进行。当您完成了实验室的工作后,您将会对影响程序性能的代码和硬件之间的交互产生强烈的欣赏。
这个实验室被分为三个部分,每个部分都有自己的把手。
在A部分中,您将编写一些简单的Y86-64程序,并熟悉Y86-64工具。
在B部分中,您将使用一个新的指令来扩展SEQ模拟器。
这两个部分将为您为实验室的核心C部分做准备,在那里您将优化Y86-64基准程序和处理器设计。


一、A部分

您将在本部分的目录sim/misc中工作。
您的任务是编写和模拟以下三个Y86-64程序。这些程序的所需行为由示例中的examples.c函数定义。一定要在每个程序的开头把你的名字和ID放在注释中。您可以测试您的程序,首先用程序YAS组装它们,然后用指令集模拟器YIS运行它们。
在所有的Y86-64函数中,您应该遵循x86-64约定来传递函数参数、使用寄存器和使用堆栈。这包括保存和恢复您使用的任何被调用的保存寄存器。

人话:把sim/misc/examples.c里面的仨函数用Y86-64程序写出来
参考书中图4.8
ps:我感觉用处不大啊,就是手写Y86-64的汇编程序呗,难怪我看做的人也不是很多。(并不打算多费时间在这上,就参考其他大佬的了)
具体详见知乎大佬的解析:早睡晚起

sum .ys:迭代求和链表元素写一个Y86-64的程序和。

即对链表中的元素进行迭代求和。您的程序应该由一些设置堆栈结构、调用一个函数、然后停止的代码组成。在这种情况下,函数应该是Y86-64代码(sum list),在功能上等同于C sum list和图1中的列表函数。使用以下三元素列表测试程序:

# Sample linked list
.align 8
ele1:
.quad 0x00a
.quad ele2
ele2:
.quad 0x0b0
.quad ele3
ele3:
.quad 0xc00
.quad 0

1 /* linked list element */
2 typedef struct ELE {
3 long val;
4 struct ELE *next;
5 } *list_ptr;
6
7 /* sum_list - Sum the elements of a linked list */
8 long sum_list(list_ptr ls)
9 {
10 long val = 0;
11 while (ls) {
12 val += ls->val;
13 ls = ls->next;
14 }
15 return val;
16 }
17
18 /* rsum_list - Recursive version of sum_list */
19 long rsum_list(list_ptr ls)
20 {
21 if (!ls)
22 return 0;
23 else {
24 long val = ls->val;
25 long rest = rsum_list(ls->next);
26 return val + rest;
27 }
28 }
29
30 /* copy_block - Copy src to dest and return xor checksum of src */
31 long copy_block(long *src, long *dest, long len)
32 {
33 long result = 0;
34 while (len > 0) {
35 long val = *src++;
36 *dest++ = val;
37 result ˆ= val;
38 len--;
39 }
40 return result;
41 }
/*Y86-64解决方案函数的C个版本。参见sim/misc/examples.c*/

代码:

# sum_list - Sum the elements of a linked list
# author: Deconx

# Execution begins at address 0
        .pos 0
        irmovq stack, %rsp      # Set up stack pointer
        call main               # Execute main program
        halt                    # Terminate program

# Sample linked list
        .align 8
ele1:
        .quad 0x00a
        .quad ele2
ele2:
        .quad 0x0b0
        .quad ele3
ele3:
        .quad 0xc00
        .quad 0

main:
        irmovq ele1,%rdi
        call sum_list
        ret

# long sum_list(list_ptr ls)
# start in %rdi
sum_list:
        irmovq $0, %rax
        jmp test

loop:
        mrmovq (%rdi), %rsi
        addq %rsi, %rax
        mrmovq 8(%rdi), %rdi

test:
        andq %rdi, %rdi
        jne loop
        ret

# Stack starts here and grows to lower addresses
        .pos 0x200
stack:

注意,应在stack下方空一行,否则汇编器会报错。
然后按操作手册来,新建一个sum.ys文件,并把代码放入。
执行
./yas sum.ys
./yis sum.yo

看到%rax是cba就是成功了

在这里插入图片描述

rsum .递归求和链表元素

编写一个Y86-64程序 rsum.ys,递归地和链表的元素。这个代码应该类似于sum.ys的代码,除了它应该使用一个函数rsum list递归地求和一个数字列表的列表,如C函数rsum list所示 在图1中列出。使用用于测试列表相同的三元素列表测试程序list.ys.

代码:

# /* rsum_list - Recursive version of sum_list */
# author: Deconx

# Execution begins at address 0
        .pos 0
        irmovq stack, %rsp      # Set up stack pointer
        call main               # Execute main program
        halt                    # Terminate program

# Sample linked list
        .align 8
ele1:
        .quad 0x00a
        .quad ele2
ele2:
        .quad 0x0b0
        .quad ele3
ele3:
        .quad 0xc00
        .quad 0

main:
        irmovq ele1,%rdi
        call rsum_list
        ret

# long sum_list(list_ptr ls)
# start in %rdi
rsum_list:
        andq %rdi, %rdi
        je return               # if(!ls)
        mrmovq (%rdi), %rbx     # val = ls->val
        mrmovq 8(%rdi), %rdi    # ls = ls->next
        pushq %rbx
        call rsum_list          # rsum_list(ls->next)
        popq %rbx
        addq %rbx, %rax         # val + rest
        ret
return:
        irmovq $0, %rax
        ret


# Stack starts here and grows to lower addresses
        .pos 0x200
stack:

注意,应在stack下方空一行,否则汇编器会报错。
然后按操作手册来,新建一个rsum.ys文件,并把代码放入。
执行
./yas rsum.ys
./yis rsum.yo

看到%rax是cba就是成功了

在这里插入图片描述

copy.ys 复制将源块复制到目标块

编写一个程序(copy.ys),将单词块从内存的一个部分复制到另一个内存(非重叠区域),计算所有复制单词的校验和(Xor)。
您的程序应该由设置堆栈框架、调用函数副本的代码组成阻止,然后停止。该函数应该在功能上等同于C函数copy block,如图1所示。使用以下三个元素的源块和目标块测试程序:

.align 8
# Source block
src:
.quad 0x00a
.quad 0x0b0
.quad 0xc00
# Destination block
dest:
.quad 0x111
.quad 0x222
.quad 0x333

代码:

/* copy_block - Copy src to dest and return xor checksum of src */
# author: Deconx

# Execution begins at address 0
        .pos 0
        irmovq stack, %rsp      # Set up stack pointer
        call main               # Execute main program
        halt                    # Terminate program

# Sample
        .align 8
# Source block
src:
        .quad 0x00a
        .quad 0x0b0
        .quad 0xc00

# Destination block
dest:
        .quad 0x111
        .quad 0x222
        .quad 0x333

main:
        irmovq src, %rdi        # src
        irmovq dest, %rsi       # dest
        irmovq $3, %rdx         # len
        call copy_block
        ret

# long copy_block(long *src, long *dest, long len)
# src in %rdi
# dest in %rsi
# len in %rdx
copy_block:
        irmovq $8, %r8
        irmovq $1, %r9
        irmovq $0, %rax
        andq %rdx, %rdx
        jmp test
loop:
        mrmovq (%rdi), %r10     # val = *src1
        addq %r8, %rdi          # src++
        rmmovq %r10, (%rsi)     # *dest = val
        addq %r8, %rsi          # dest++
        xorq %r10, %rax         # result ^= val
        subq %r9, %rdx          # len--.  Set CC
test:
        jne loop                # Stop when 0
        ret

# Stack starts here and grows to lower addresses
        .pos 0x200
stack:

这道题几乎与4-7完全相同

注意,应在stack下方空一行,否则汇编器会报错。
然后按操作手册来,新建一个copy_block.ys文件,并把代码放入。
执行
./yas copy_block.ys
./yis copy_block.yo

看到%rax是cba就是成功了

在这里插入图片描述

二、B部分

您将在这部分的目录sim/seq中工作。
B部分中的任务是扩展SEQ处理器以支持iaddq,在家庭作业问题4.51和4.52中描述。要添加此说明,
您将修改文件的seq-full.hcl,它实现了CS: APP3e教科书中描述的SEQ版本。此外,它还包含了您
的解决方案所需要的一些常量的声明。
HCL文件必须以包含以下信息的标题注释开头:

  1. 你的名字和身份证。
  2. 对iaddq指令所需的计算方法的描述。使用CS: APP3e文本中图4.18中的irmovq和OPq的描述作为指南。
    构建和测试您的解决方案
    一旦你完成了修改序列的全部。hcl文件,然后你将需要基于这个hcl文件建立一个新的SEQ模拟器(ssim)的实例,然后测试它:
    建立一个新的模拟器。你可以使用make来构建一个新的SEQ模拟器:
    unix> make VERSION=full
    这构建了一个使用您在seq-full中指定的控制逻辑的ssim版本。要保存键入操作,您可以在Makefile中给与VERSION=full。
    在一个简单的Y86-64程序上测试你的解决方案。对于您的初始测试,我们建议在TTY模式下运行简单的程序,如asumi.yo(测试iaddq),并将结果与ISA模拟进行比较:
    unix> ./ssim -t …/y86-code/asumi.yo
    如果ISA测试失败,那么您应该通过以GUI模式单步进模拟器来调试实现:
    unix> ./ssim -g …/y86-code/asumi.yo
    使用基准测试程序重新测试您的解决方案。一旦你的模拟器能够正确地执行小程序,那么你就可以自动在Y86-64基准测试程序上测试它。…/y86-code:
    unix> (cd …/y86-code; make testssim)
    这将在基准测试程序上运行ssim,并通过将生成的处理器状态与来自高级ISA模拟的状态进行比较来检查其正确性。请注意,这些程序都没有测试所添加的指令。您只是在确保您的解决方案没有为原始指令注入错误。查看文件…/y86-code/README文件了解更多细节。
    执行回归测试。一旦您能够正确地执行基准测试程序,那么您就应该在…/ptest中运行广泛的回归测试集。要测试除iaddq之外的所有内容并leave:
    unix> (cd …/ptest; make SIM=…/seq/ssim)
    要测试iaddq的实现:
    unix> (cd …/ptest; make SIM=…/seq/ssim TFLAGS=-i)
    有关SEQ模拟器的更多信息,请参阅关于Y86-64处理器模拟器(simguide.pdf)的分发CS: APP3e指南。
1 /*
2 * ncopy - copy src to dst, returning number of positive ints
3 * contained in src array.
4 */
5 word_t ncopy(word_t *src, word_t *dst, word_t len)
6 {
7 word_t count = 0;
8 word_t val;
9
10 while (len > 0) {
11 val = *src++;
12 *dst++ = val;
13 if (val > 0)
14 count++;
15 len--;
16 }
17 return count;
18 }
/*图2:ncopy函数的C版本。请参阅sim/pipe/ncopy.c*/

这块就不越俎代庖了,大家看大佬的就好:大佬答案
测试方法

make VERSION=full
cd seq/
./ssim -t ../y86-code/asumi.yoY86-64 Processor: seq-full.hcl
cd ../ptest; make SIM=../seq/ssim TFLAGS=-i

在这里插入图片描述
在这里插入图片描述

三、C部分

您将在本部分的目录sim/pipe中工作。
图2中的ncopy函数将一个len-元素整数数组src复制到一个不重叠的dst中,返回src中包含的正整数的计数。图3显示了ncopy的基线Y86-64版本。文件pipe-full.hcl包含一个针对PIPE的HCL代码的副本,以及一个常量值IIADDQ的声明。
您在C部分中的任务是修改ncopy.ys和pipe-full.hcl的目标是制作ncopy.ys。跑得越快越好。
你将提交两个文件:pipe-full.hcl和ncopy.ys。每个文件都应该以一个包含以下信息的标题注释开头:
你的名字和身份证。
对您的代码的高级描述。在每种情况下,描述您如何以及为什么修改代码。

您可以自由地做任何您想要的修改,并有以下限制:

  1. 你的ncopy.ys函数必须适用于任意大小的数组。您可能会试图通过简单地编码64个复制指令来硬连接64个元素数组的解决方案,但这将是一个坏主意,因为我们将根据其在任意数组上的性能对您的解决方案进行分级。
  2. 你的ncopy.ys函数必须与YIS一起正确运行。通过正确地复制,我们的意思是它必须正确地复制src块并返回(以%rax表示)正确的正整数数。
  3. ncopy文件的组装版本的长度不能超过1000字节。您可以使用提供的脚本check-len.pl检查嵌入了ncopy函数的任何程序的长度:unix> ./check-len.pl < ncopy.yo
  4. 你的pipe-full.hcl实现必须通过中的回归测试:…/y86-code和 …/ptest。(没有测试iaddq的-i标志)。

除此之外,如果你认为iaddq指令会有帮助,你就可以自由地执行iaddq指令。您可以对ncopy进行任何保留语义的转换。它的功能,如重新排序指令,用单个指令替换指令组,删除一些指令,以及添加其他指令。您可能会发现在CS: APP3e的第5.8节中阅读关于循环展开的信息很有用。

1 ##################################################################
2 # ncopy.ys - Copy a src block of len words to dst.
3 # Return the number of positive words (>0) contained in src.
4 #
5 # Include your name and ID here.
6 #
7 # Describe how and why you modified the baseline code.
8 #
9 ##################################################################
10 # Do not modify this portion
11 # Function prologue.
12 # %rdi = src, %rsi = dst, %rdx = len
13 ncopy:
14
15 ##################################################################
16 # You can modify this portion
17 # Loop header
18 xorq %rax,%rax # count = 0;
19 andq %rdx,%rdx # len <= 0?
20 jle Done # if so, goto Done:
21
22 Loop: mrmovq (%rdi), %r10 # read val from src...
23 rmmovq %r10, (%rsi) # ...and store it to dst
24 andq %r10, %r10 # val <= 0?
25 jle Npos # if so, goto Npos:
26 irmovq $1, %r10
27 addq %r10, %rax # count++
28 Npos: irmovq $1, %r10
29 subq %r10, %rdx # len--
30 irmovq $8, %r10
31 addq %r10, %rdi # src++
32 addq %r10, %rsi # dst++
33 andq %rdx,%rdx # len > 0?
34 jg Loop # if so, goto Loop:
35 ##################################################################
36 # Do not modify the following section of code
37 # Function epilogue.
38 Done:
39 ret
40 ##################################################################
41 # Keep the following label at the end of your function
42 End:
/*ncopy函数的基线Y86-64版本。请参阅sim/pipe/ncopy.ys*/

解答:

实现iaddq指令

pipe-full.hcl改动部分,可参考PartB

# Is instruction valid?
bool instr_valid = f_icode in 
	{ INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ,
	  IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ, IIADDQ};
# Does fetched instruction require a regid byte?
bool need_regids =
	f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, 
		     IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ};

# Does fetched instruction require a constant word?
bool need_valC =
	f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ};
## What register should be used as the B source?
word d_srcB = [
	D_icode in { IOPQ, IRMMOVQ, IMRMOVQ , IIADDQ} : D_rB;
	D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;
	1 : RNONE;  # Don't need register
];

## What register should be used as the E destination?
word d_dstE = [
	D_icode in { IRRMOVQ, IIRMOVQ, IOPQ, IIADDQ} : D_rB;
	D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;
	1 : RNONE;  # Don't write any register
## Select input A to ALU
word aluA = [
	E_icode in { IRRMOVQ, IOPQ } : E_valA;
	E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ} : E_valC;
	E_icode in { ICALL, IPUSHQ } : -8;
	E_icode in { IRET, IPOPQ } : 8;
	# Other instructions don't need ALU
];

## Select input B to ALU
word aluB = [
	E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, 
		     IPUSHQ, IRET, IPOPQ, IIADDQ} : E_valB;
	E_icode in { IRRMOVQ, IIRMOVQ } : 0;
	# Other instructions don't need ALU
];
## Should the condition codes be updated?
bool set_cc = E_icode == (E_icode == IOPQ || E_icode == IIADDQ)&&
	# State changes only during normal operation
	!m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT };

在sim/pipe输入以下命令测试

./psim -t ../y86-code/asumi.yo
(cd ../ptest;make SIM=../pipe/psim TFLAGS=-i)
(cd ../ptest;make SIM=../pipe/psim)

测试成功
在这里插入图片描述
通过这两个命令测试CPE

./correctness.pl
./benchmark.pl

得:在这里插入图片描述
出了点问题,改完iaddrq指令后,CPE全都变成小于1了。。。不知道为啥?
网上也没找到原因,重新替换也不好使。


总结

这一章比较乱,我的重心也没放在这里。最近事太多心理上也十分的烦躁、焦虑。希望以后可以恢复过来,然后我再次跟这道题抗争到底!我能行的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/984920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android发布依赖到 Jitpack

前言 我们在日常开发中&#xff0c;经常会用到第三方开源的库文件&#xff0c;有的来自JCenter&#xff0c;Maven Central&#xff0c;google等。但是随着JCenter的弃用&#xff0c;现在用的最多的还是Maven Central&#xff0c;google。今天我们就自己亲自发布一个依赖。 现…

三秋农忙,自动驾驶农机保驾护航

“三秋”&#xff08;收获、播种、整地&#xff09;是一年中重要而忙碌的农事季节&#xff0c;水稻、棉花、玉米等农作物收获时期&#xff0c;也是小麦、蔬菜等秋种的好时间&#xff0c;还是各类农作物进入秋管的重要期。 随者农业科技发展&#xff0c;北斗导航农机自动驾驶系…

Json“牵手”唯品会商品详情数据方法,唯品会商品详情API接口,唯品会API申请指南

唯品会是中国最大的会员制特卖电商平台之一&#xff0c;于2008年创立&#xff0c;唯品会主营业务为互联网在线销售品牌折扣商品&#xff0c;涵盖名品服饰鞋包、美妆、母婴、居家等各大品类2。唯品会采取供应链直采模式&#xff0c;与全球3000多家品牌及供应商合作&#xff0c;直…

网络货运平台服务模式,你真的了解吗?

在当今的“互联网”时代&#xff0c;网络货运平台已经成为物流行业中的重要力量。 长期以来&#xff0c;货物运输行业处于“小、散、乱、差”的状态&#xff0c;存在信息不对称、运输环节层层分包等问题。数字时代到来&#xff0c;各行各业都在进行数字升级&#xff0c;物流行…

德国金融监管机构网站遭遇大规模DDoS攻击后“瘫痪”

德国波恩的BaFin大楼 BaFin是负责监督和监管德国金融机构和市场的金融监管机构&#xff0c;其职责是确保德国金融体系的稳定性、完整性和透明度。 此外&#xff0c;BaFin 的网站还为企业和消费者提供银行、贷款和财产融资等方面的信息。它还提供消费者帮助热线和举报人信息共…

分享一些领英添加客户的话术

昨天一个朋友很开心地跟我分享她在领英找到的一个非常优质的客户&#xff0c;她说这个客户很忠诚&#xff0c;基本上每年都会回来找她下单&#xff0c;这两年持续的下单&#xff0c;也没有对比价格&#xff0c;特别感恩遇见这样的客户。 也许是行业和产品不同&#xff0c;我领…

[C++]杨辉三角

目录 题目 解题思路 代码实现 获取数字 打印函数 主函数 全部代码 运行结果 题目 给定一个非负整数numRows &#xff0c;生成「杨辉三角」的前numRows行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 解题思路 第k列的第i个数字的值第k-1列的(…

合宙Air724UG LuatOS-Air LVGL API控件-加载器(Spinner)

加载器(Spinner) 示例代码 spinner lvgl.spinner_create(lvgl.scr_act(), nil) lvgl.obj_set_size(spinner, 100, 100) lvgl.obj_align(spinner, nil, lvgl.ALIGN_CENTER, 0, 0) 创建 通过 lvgl.spinner_create 就可创建一个加载器&#xff0c;本身自带动画效果。 spinner …

PageHelper分页原理解析

大家好&#xff0c;我是Leo! 今天给大家带来的是关于PageHelper原理的解析&#xff0c;最近遇到一个SQL优化的问题&#xff0c;顺便研究了一下PageHelper的原理&#xff0c;毕竟也是比较常用&#xff0c;源码也比较好看的懂&#xff0c;如果感兴趣的小伙伴可以跟着过程去DEBUG源…

【优选算法】—— 前缀和算法

前言&#xff1a; 本期&#xff0c;我将要带大家学习的是有关前缀和算法的学习&#xff01;&#xff01;&#xff01; 目录 &#xff08;一&#xff09;什么是前缀和算法 &#xff08;二&#xff09;题目讲解 1、【模板】前缀和 2、【模板】二维前缀和 3、 和可被K整除的…

简明SQL截断和偏移指南:掌握LIMIT实现数据筛选

以下是用到的表。 截断 LIMIT 用于限制查询结果返回的行数&#xff0c;即最多返回多少行数据。 例如&#xff0c;返回前两行数据。 例如&#xff0c;从第二个数据开始返回两条数据&#xff08;从0开始计算&#xff09;。 偏移 OFFSET 用于指定查询结果的起始位置&#xff0c…

园区宿舍水电表改造解决方案

随着社会经济的快速发展&#xff0c;人们对生活品质的要求不断提高&#xff0c;园区宿舍作为众多企业员工和学生的居住场所&#xff0c;水电资源的合理使用和节约越来越受到关注。为了更好地满足人们对生活品质的需求&#xff0c;提高水电资源的利用效率&#xff0c;园区宿舍水…

PHP8中查询数组中指定元素-PHP8知识详解

php是使用最广泛的web编程语言&#xff0c;数组是一个数据集合&#xff0c;数组是一种非常常用的数据类型。在操作数组时&#xff0c;有时我们需要查询数组中是否有某个指定元素。在实际的程序开发中&#xff0c;我们用到了下列方法来查询数组中指定的元素&#xff1a;使用arra…

postman返回值乱码

描述&#xff1a; 在使用postman测试接口的时候&#xff0c;结果正常返回&#xff0c;但是乱码了&#xff0c;这个一般都是编码集设定的问题,后端接口是使用的springmvc Controller public class TestController(){RequestMapper("/test8")ResponseBodypublic Strin…

C++QT day2

作业 1> 封装一个结构体&#xff0c;结构体中包含一个私有数组&#xff0c;用来存放学生的成绩&#xff0c;包含一个私有变量&#xff0c;用来记录学生个数&#xff0c; 提供一个公有成员函数&#xff0c;void setNum(int num)用于设置学生个数 提供一个公有成员函数&…

微服务05-Docker基本操作

Docker的定义 1.什么是Docker Docker是一个快速交付应用、运行应用的技术&#xff1a; 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通过一行命令完…

程序分区:全局区、常量区、栈区、堆区、代码区

#include <iostream> using namespace std; //全局变量 int g_a 10; int g_b 10; //全局常量 const int c_g_a 10; const int c_g_b 10;int main() { //局部变量 int a 10; int b 10; //打印地址 cout << "局部变量a地址为&#xff1a; " <…

第一章 微信小程序入门

文章目录 一.关于小程序思维导图二.详细讲解1.初始微信小程序1.1 什么是微信小程序1.2 微信小程序的特点1.3微信小程序的发展前景1.4微信小程序的宿主环境 2.微信小程序开发前的准备2.1 注册微信小程序的开发账户2.2获取微信小程序的AppID2.3安装微信开发者工具2.4创建微信小程…

pytorch学习——循环神经网络RNN讲解及其实现

参考书籍&#xff1a;8.6. 循环神经网络的简洁实现 — 动手学深度学习 2.0.0 documentation 参考视频&#xff1a;54 循环神经网络 RNN【动手学深度学习v2】_哔哩哔哩_bilibili 一.介绍 循环神经网络RNN&#xff08;Recurrent Neural Network &#xff09;是一类广泛应用于序列…