table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}
1、什么是算法?
算法是解决问题或达成预期目标的一个明确的、循序渐进的过程。
2、一个16位寄存器可以存储多少种不同的模式?作为(补码)有符号整数,该寄存器能存储的最大值和最小值分别是多少?作为无符号整数,最大值和最小值又分别是多少?
一个16位寄存器可以存储 $2^{16}$(约65,536)种不同的模式。
– 有符号整数最大值是
32767
(0x7FFF),最小值是
-32768
(0x8000)。
– 无符号整数最大值是
65535
(0xFFFF),最小值是
0
(0x0000)。
3、使用标准 ASCII 表,哪 4 个十六进制字节可以表示字符串“Fred”?
在标准 ASCII 表中,“F”对应十六进制
46
,“r”对应
72
,“e”对应
65
,“d”对应
64
,所以表示字符串“Fred”的 4 个十六进制字节是
46726564
。
4、十六进制数 0x45617379 对应的 ASCII 字符串是什么?
根据 ASCII 编码规则,
0x45
对应
'E'
,
0x61
对应
'a'
,
0x73
对应
's'
,
0x79
对应
'y'
,所以对应的字符串是
'Easy'
。
5、判断对错:二进制数中1的数量越多,该数越大。为什么对或错?
错误。二进制数的大小由其位权和每一位上的数值共同决定,并非仅取决于1的数量。
例如,8位二进制数
01111111
(十进制 127)比
10000000
(十进制 -128)大,但后者1的数量更少。
6、为什么为Windows奔腾IV电脑创建的可执行文件在基于PowerPC的苹果电脑上无法运行(没有特殊软件支持的情况下)?
不同的操作系统和CPU架构不兼容,为一种操作系统(如Windows奔腾IV电脑的操作系统)创建的可执行文件无法在不同的操作系统(如基于PowerPC的苹果电脑的操作系统)上运行。
软件供应商会针对不同的CPU(如奔腾4 CPU和PowerPC CPU)销售不同版本的程序,许多程序也有“所需配置”说明,特定计算机必须具备一定的内存或特定的显卡才能正常工作。
极端情况下,程序员需要为不同系统独立编写相关程序。
7、软件相对于硬件在执行特定操作方面最重要的缺点是什么?
速度。在软件中执行特定操作通常比在硬件中慢约1000倍,在JVM上用Java进行硬核计算可能比用C++编译的特定于芯片的机器语言执行相同计算慢得多。
8、可以使用哪些语言为 Java 虚拟机(JVM)编写程序?
可以使用 Java、Scala、Kotlin、Groovy 等语言为 JVM 编写程序,因为编译器可将这些语言的代码转换为 JVM 能够执行的字节码形式。
(原答案中的 C++ 和 Pascal 通常不能直接为 JVM 编写程序,这里给出常见的可用于 JVM 编程的语言)
9、编写一个程序,读取一个十进制浮点数,并输出其对应的 IEEE 64 位十六进制表示。
需额外查阅资料编写程序来实现读取十进制浮点数并输出其 IEEE 64 位十六进制等效值的功能。
10、在复杂指令集计算机(CISC)还是精简指令集计算机(RISC)上,取指 – 执行周期更复杂?为什么?
CISC 与 RISC 在取指 – 执行周期上的区别
在 CISC 计算机上,取指 – 执行周期更复杂。CISC 芯片能够将大块数据从一个内存位置移动到另一个内存位置,但对于复杂操作,特定程序或应用可能需要使用许多指令来完成任务。
而 RISC 芯片可能需要将每个字节或字移入 CPU 再移回内存,且每一步都要获取并解释移动特定字节的指令。不过,其指令集设计简单,指令执行时间大致相同,通常能在单个机器周期内执行,在取指 – 执行周期方面相对不那么复杂。
11、以下哪些操作是非法的,为什么? • bipush 7 • bipush -7 • sipush 7 • ldc -7 • ldc2 -7 • bipush 200 • ldc 3.5 • sipush -300 • sipush -300.0 • ldc 42.15
`ldc2 -7`、`bipush 200`、`sipush -300.0` 是非法的。
- `ldc2` 用于推送双字常量,如 `long` 或 `double`,不能用于推送 -7;
- `bipush` 用于推送 1 字节有符号整数,范围是 -128 到 127,200 超出范围;
- `sipush` 用于推送 2 字节有符号整数,不能用于推送浮点数 -300.0。
12、如何使用移位运算将一个整数乘以8?
可使用左移运算(
ishl
),因为左移操作相当于将值乘以2的幂,乘以8即乘以2的3次方,所以将整数左移3位即可。
13、计算机如何判断给定的一行包含的是指令、注释还是汇编指令?
在jasmin中,判断方式如下:
注释方面
:一行中跟在分号(
;
)后的部分为注释,汇编器会忽略注释内容;
指令方面
:对应计算机机器语言或字节码的语句为指令,很多情况下可通过查找汇编器中存储的表来生成对应字节码;
汇编指令方面
:大多数汇编指令以句点(
.
)开头,如
.class
指令。
14、如果忘记使用 .limit 指令,Jasmin 程序还能运行吗?
能运行,但如果省略
.limit
指令,将应用默认限制,即一个项目的限制,仅够存储一个
int
或
float
类型的数据,对于更大类型则不够。
15、与圣诞节(总是12月25日)不同,复活节的日期每年都在变化。有一个确定复活节日期的布彻算法,所有值均为整数,所有除法均为整数除法,mod表示整数取模(除法后的余数)。若给定相关年份y,按照以下步骤计算:设a为y对19取模;设b为y除以100的商;设c为y对100取模;设d为b除以4的商;设e为b对4取模;设f为(b + 8)除以25的商。请用Python代码实现上述计算步骤。
以下是实现上述计算步骤的Python代码:
y = int(input("请输入相关年份:"))
a = y % 19
b = y // 100
c = y % 100
d = b // 4
e = b % 4
f = (b + 8) // 25
print("a的值为:", a)
print("b的值为:", b)
print("c的值为:", c)
print("d的值为:", d)
print("e的值为:", e)
print("f的值为:", f)
这段代码首先让用户输入相关年份
y
,然后按照布彻算法的规则计算出
a
、
b
、
c
、
d
、
e
、
f
的值,并将这些值打印输出。
16、goto和goto w有什么区别?是否存在对应的ifne w?
goto w
与普通
goto
在大多数方面相似,但
goto w
后面跟随一个全尺寸整数,允许程序员向前或向后跳转约 20 亿字节,而普通
goto
跳转范围有限。不存在直接对应的
ifne w
,但汇编器可在程序员不知情或不配合的情况下设计等效方案,如通过“绕过分支”的方式模拟条件(宽)分支跳转到远距离位置。
17、简述移位操作的相关知识,包括不同类型数据移位的结果、JVM提供的移位操作、移位操作的应用等
对于有符号量,逻辑右移总会得到正数结果,算术右移仅当初始值为负时得到负数结果;对于无符号值,左移相当于乘以2的幂,逻辑右移相当于除以2的幂。
JVM提供以下操作,适用于
int
和
long
类型:
?shl
(左移)
?shr
(算术右移)
?ushr
(逻辑右移)
移位操作常用于将已知位集放到特定位置,用于后续按位与、或、异或操作。此外,移位操作可用于整数乘法,如将整数乘以8可通过左移3位实现。
18、物理计算机存在哪些存储限制是Java虚拟机(JVM)栈可以忽略的?
物理计算机存在以下存储限制,而JVM栈可以忽略:
物理计算机通常只有一个CPU和一组主内存,两个同时运行的函数可能会竞争寄存器、内存存储等资源;而JVM中每个方法都假定在自己独立的环境中运行,改变一个方法中的局部变量不会影响其他方法。
物理计算机的机器容量有限,如PowerPC芯片只有32个寄存器用于计算,基于奔腾的Windows PC的寄存器更少;而JVM机器栈实际上具有无限的深度和无限的局部变量容量。
19、解释内存管理如何允许两个程序同时使用相同的内存位置而不发生冲突。
内存管理
内存管理通过将程序引用的逻辑地址重新解释为特定的物理位置(可能在硬盘上)来实现这一点。程序不直接引用内存中的特定物理位置,而是使用逻辑地址,由内存管理器将其转换为物理地址。
地址翻译方式
直接地址翻译
若硬件地址转换关闭,物理地址与逻辑地址逐位相同。
通常用于只运行一个程序的专用计算机以提高速度。
页地址翻译
可防止两个进程访问相同的物理地址。
块地址翻译(PowerPC)
使用特殊用途的 BAT 寄存器定义特殊的物理内存块。
若逻辑地址对应 BAT 寄存器标记的内存区域,则跳过虚拟内存过程,直接从 BAT 寄存器读取相应物理地址。
优势
不同程序的逻辑地址可被映射到不同的物理地址。
允许不同程序同时使用相同的逻辑内存位置而不发生冲突。
20、“一系列芯片”这个概念是什么意思?
芯片系列定义与示例
一系列芯片是指由同一制造商生产的、在技术上具有传承和发展关系的一组芯片。
示例
英特尔 80×86 系列
起始芯片
:英特尔 4004
后续发展
:
8008
8088
80086
80286
80386
80486
各种奔腾芯片
奔腾系列演进
奔腾 4
:是奔腾、奔腾 II 和奔腾 III 的进一步发展
奔腾
:本身源自以英特尔 8088 开头的一系列编号芯片
Power 系列
整体系列
:Power
子系列
:PowerPC
21、BX寄存器和BL寄存器有什么区别?
BX
和
BL
都是
8088
的通用寄存器。
BX
是一个
16 位寄存器
。
BL
是从
BX 寄存器
中细分出来的
8 位寄存器
,具体来说,它是
BX 的低 8 位部分
。
对其中一个寄存器的修改会影响到另一个,因为它们属于
同一寄存器的不同部分
。
22、以下段:偏移对对应的实际地址是什么?a. 0000:0000 b. ABCD:0000 c. A000:BCD0 d. ABCD:1234
a. 0x00000;
b. 0xABCD0;
c. 0xABCD0 这里计算有误,正确结果应为 0xA0000 + 0xBCD0 = 0xABCD0;
d. 0xABD14 这里计算有误,正确结果应为 0xABCD0 + 0x1234 = 0xABF04。
计算方法是将段寄存器的值乘以 16(即左移 4 位),再加上偏移量。如
a 中 0x0000 乘以 16 还是 0x0000,加上 0x0000 得 0x00000;
b 中 0xABCD 乘以 16 为 0xABCD0,加 0x0000 得 0xABCD0;
c 中 0xA000 乘以 16 为 0xA0000,加 0xBCD0 得 0xABCD0;
d 中 0xABCD 乘以 16 为 0xABCD0,加 0x1234 得 0xABF04。
23、JA和JG有什么区别?
JA
用于比较无符号数,是基于“高于”(Above)概念的条件跳转指令;
JG
用于比较有符号整数,是“大于”(Greater)时跳转的指令。
24、ADD WORD PTR [4000h], 1和ADD BYTE PTR [4000h], 1有什么区别?
以下是给定【文本内容】调整为markdown格式的输出:
`ADD WORD PTR [4000h], 1` 会将地址 `0x4000` 处的 16 位值加 1;
`ADD BYTE PTR [4000h], 1` 会将地址 `0x4000` 处的 8 位值加 1。
25、RISC芯片相对于CISC芯片的优势和劣势分别是什么?
优势:
设计通常小巧、简洁、简单,未来版本也能保持,能抵抗“功能蔓延”,而CISC芯片新版本通常会增加更多指令、功能和复杂性,阻碍向后兼容性;
单个时钟周期可能对应一条机器指令,在某些情况下每个时钟周期能完成更多工作;
可专注设计硬件以高效完成简单任务。
劣势:
执行罕见或复杂任务时可能需要更多时间,且需要复杂的编译器来生成合适的指令集。
26、Power架构设计灵活性的示例有哪些?
是现有(主要来自摩托罗拉和IBM)设计之间的灵活折衷,芯片实际上是一系列交叉兼容的芯片,在架构细节上有很大差异,如PowerPC有32位和64位字长变体。
单个芯片在与软件交互的方式上有极大灵活性,任何Power芯片都可以以大端和小端格式存储数据。
开发重点并非仅专注于生产更新、更大的机器,从一开始,低端桌面甚至嵌入式系统控制器就是目标市场的一部分。
联盟计划最终扩展到64位领域,并在原始(32位)设计中定义了可扩展的指令集来处理64位数量。
PowerPC能够处理数据存储格式的大量变化。
27、PowerPC算术指令使用的三参数格式有什么优点?
三参数格式与可用寄存器数量较多相结合,为程序员或编译器在执行计算和存储中间结果时提供了极大的灵活性,也让计算机在需要时能灵活调整计算结构。
28、对于流水线操作,为什么所有指令大小相同很重要?
在一些处理器中,指令长度不同,例如奔腾处理器指令长度从单字节到约15字节不等,加载长指令可能比短指令长15倍,加载长指令时流水线其余部分可能闲置。而像PowerPC这种所有指令长度相同的处理器,可在一次操作中加载指令,能保持流水线满负荷运行。
29、如何通过重新排列计算顺序来加速 PowerPC 程序?
PowerPC 芯片并行处理与指令优化
PowerPC 芯片拥有多个执行模块,可并行处理不同类型指令。
通过重新排列计算顺序,可以让无依赖关系、不同类型的指令并行执行。例如:
将不同类型指令混合排列
使各执行模块同时工作
避免同类型指令连续执行导致的效率降低
此外,智能编译器能够利用 32 个通用寄存器进行计算分配,减少指令间依赖,从而提升程序运行速度。
30、8088和奔腾处理器之间的四大主要变化是什么?
寄存器方面
:
– 寄存器方面:奔腾处理器有更多寄存器,8个通用寄存器扩展为32位并获得新名称,如AX变为EAX;16位IP寄存器变为32位EIP寄存器;EFLAGS寄存器容纳32个标志而非16个。
总线和操作方面
:
– 奔腾处理器有更多总线线路、更多选项、更多指令,字长为32位,多数操作处理32位数据量。
段寄存器方面
:
– 奔腾处理器有6个段寄存器(CS、SS、DS、ES、FS和GS),用于优化对常用内存区域的访问,而8088只有4个。
操作模式方面
:
– 奔腾处理器创建了多种不同操作模式以支持多任务处理,而8088中任何程序都可无限制访问整个寄存器集及系统内容。
31、奔腾II中重新排序指令提取的目的是什么?
奔腾II的解码器只能处理非常简单的指令,重新排序指令提取可使指令与解码器对齐。若指令队列中的后三条指令中有复杂指令,会自动将其放入解码器1,因这类复杂指令较少,无需为第二个和第三个解码器增加此(昂贵的)处理能力。
32、为什么爱特梅尔AVR在其设计中采用精简指令集计算机(RISC)原则?
爱特梅尔AVR的RISC设计原则
爱特梅尔AVR采用RISC设计原则是为了兼顾速度和简单性。其特点包括:
指令数量相对较少
:这使得现有指令长度较短(2字节),相比PowerPC的4字节或奔腾的最多15字节。
执行速度快
:由于指令长度短,执行效率更高。
指令长度标准化
:每条指令长度标准化为16位,包括必要参数。
指令集优化
:专门针对微控制器的常见需求进行了调整。
33、典型计算机的哪些组件在爱特梅尔AVR微控制器上找不到?
爱特梅尔AVR微控制器特性对比
浮点运算支持
:爱特梅尔AVR微控制器没有对浮点运算的支持,而典型计算机通常具备浮点运算能力。
内存容量
:AVR微控制器的内存少于10000字节,相比之下,典型计算机拥有更大的内存。
指令集架构
:AVR微控制器采用精简指令集计算机(RISC)设计原则,指令数量相对较少,这与典型计算机的复杂指令集形成对比。
34、Atmel是冯·诺伊曼架构的例子吗?为什么是或不是?
Atmel不是冯·诺伊曼架构的例子。
冯·诺伊曼架构
:
控制模式和数据模式可存于同一内存。
现代计算机通过使用方式来区分它们。
Atmel架构(哈佛架构)
:
将内存分为不同的存储区。
程序存储和数据存储是分开的。
程序存储在FLASH ROM存储区。
变量存储在包含寄存器和通用RAM的存储区。
35、RAM和ROM有什么区别?
存储器类型简介
RAM(随机存取存储器)
可对任意位置进行读写操作
属于
易失性存储器
,断电后数据丢失
包含两种子类型:
动态随机存取存储器
(DRAM)
价格便宜、更紧凑
需定期刷新
静态随机存取存储器
(SRAM)
无需刷新
访问速度快
占用芯片空间大、成本高
ROM(只读存储器)
写入操作困难
,通常需要特殊操作和设备
属于
非易失性存储器
,断电后数据仍保留
类型包括:
普通ROM
由芯片制造商编程
不可更改
可编程只读存储器
(PROM)
可由用户“烧录”一次
可擦除可编程只读存储器
(EPROM)
可通过紫外线擦除后重新编程
36、为什么每字节静态随机存取存储器(SRAM)比动态随机存取存储器(DRAM)成本更高?
因为每个SRAM存储位通常需要约6到10个晶体管来实现,这意味着1字节的SRAM在芯片上占用的空间最多可达DRAM的10倍,成本也最多可达10倍。
37、Atmel AVR的内存库有哪些,它们的用途是什么?
Atmel AVR 内存库
Atmel AVR有三个独立的内存库:
1. 程序代码只读库
构成:FLASH ROM
用途:用于存储可执行机器代码
特点:
程序执行期间代码不会改变
从AVR角度看是只读的
断电后信息不丢失
只能通过外部设备编程或重新编程
2. 高速读写库
构成:SRAM(静态随机存取存储器)
用途:用于存储程序变量
AT90S2313的SRAM少于256字节,分为三个子库:
前32字节用作通用寄存器 R0 – R31
接下来64字节用作I/O寄存器
其余用作通用内存存储寄存器
3. 长期存储库
构成:EEPROM
特点:非易失性的
用途:用于存储断电后仍需保留的程序数据,如日志或配置信息
38、看门狗定时器的功能是什么?
看门狗定时器的工作原理与应用
看门狗定时器作为普通定时器工作,它向CPU发送的“信号”相当于按下复位按钮,能使系统在已知(正常)状态下重启。
程序有责任定期重置看门狗(有时称为“踢”它)以防止其触发。
在程序出现无限循环等错误时,看门狗定时器可生成与复位按钮或上电事件相同的中断,为系统提供一定保护,避免程序错误带来的不良影响,如避免烤面包机烧损、厨房起火等情况。
此外,在交通灯程序中,可利用看门狗定时器查找可能的程序错误,在其触发时让程序进入特定的预编程正常状态或紧急状态。
39、描述Atmel使LED反复闪烁的过程。
要使连接到引脚6的LED闪烁,程序员首先要确保数据方向寄存器(DDR)的第六位设置为1,将该引脚配置为输出设备;
然后将数据寄存器的第六位的值设置为1,使引脚电压升高(约3 – 5伏),点亮LED;
将该位设置为0,相应地将引脚电压设置为接近0伏,关闭LED。
通过反复进行这样的操作,可使LED反复闪烁。
同时,可利用AVR内置的定时器来控制LED闪烁的时间间隔,将内部寄存器设置为初始值,定时器对时钟脉冲进行计数,当内部寄存器从全1计数到全0时,定时器触发,此时CPU可改变LED的状态。
40、在像奔腾这样的典型计算机上,通常通过索引模式访问数组元素。那么JVM使用什么来代替这种方式访问数组元素呢?
在JVM上,没有真正意义上的“地址模式”。取而代之的是,将数组基地址对应的数字和偏移量这两个数字压入栈中,并执行一个特殊用途的操作来适当地访问数组。
实际上,根据需要完成的操作,有五种特殊用途的操作,按大致所需顺序依次为:
创建新数组
将数据项加载到数组元素中
从数组元素中检索数据项
确定数组的长度
在数组不再需要时销毁数组
41、字段和局部变量有什么区别?
局部变量与字段
局部变量
局部变量是与每个JVM方法关联的一组可自由、随机且按任意顺序访问的内存位置。局部变量通过顺序编号引用,从0开始,每个变量存储标准字长模式。双字模式(如长整型和双精度浮点型)需占用两个相邻变量。
字段
字段是类或对象的属性,具有以下特点:
有命名
可通过访问修饰符定义其访问权限
可定义是否为静态字段或是否不可变
分类
静态字段
:与类关联
非静态字段
:与对象关联
生命周期
创建
:
非静态字段在对象创建时自动创建
静态字段在类加载时自动创建
销毁
:在垃圾回收时销毁
数据操作
存储和加载字段数据使用
putfield
和
putstatic
等操作
与局部变量的加载和存储操作不同
42、以下方法对应的类型字符串是什么?a. float toFloat(int) b. void printString(String) c. float average(int, int, int, int) d. float average(int []) e. double [][] convert(long [][]) f. boolean isTrue(boolean)
a. (I)F;
b. (Ljava/lang/String;)V;
c. (IIII)F;
d. ([I)F;
e. ([[J)[[D;
f. (Z)Z
43、
方法有什么特别之处?
在初始化对象时,为确保对象拥有所有超类的属性,需调用当前对象的初始化方法,由于这是初始化方法,计算机必须使用
invokespecial
指令来调用
<init>
方法。此外,
invokespecial
指令可用于调用实例初始化方法
<init>
、当前对象的私有方法或当前对象超类中的方法。
44、每个JVM类文件的第四个字节是什么?
给定的文本内容调整为 Markdown 格式如下:
0xBE。因为任何 JVM 类文件的前 4 个字节是魔数 `0xCAFEBABE`,按网络顺序(大端序)存储为 `0xCA`、`0xFE`、`0xBA`、`0xBE`,所以第四个字节是 `0xBE`。
45、编写一个 Time 类来支持时间的算术运算。例如,1:35 + 2:15 是 3:50,但 1:45 + 2:25 是 4:10。
以下是一个 Python 实现的 Time 类示例:
class Time:
def __init__(self, hours, minutes):
self.hours = hours
self.minutes = minutes
def __add__(self, other):
total_minutes = self.hours * 60 + self.minutes + other.hours * 60 + other.minutes
new_hours = total_minutes // 60
new_minutes = total_minutes % 60
return Time(new_hours, new_minutes)
def __str__(self):
return f'{self.hours}:{self.minutes:02d}'
# 测试示例
time1 = Time(1, 35)
time2 = Time(2, 15)
result1 = time1 + time2
print(result1) # 输出 3:50
time3 = Time(1, 45)
time4 = Time(2, 25)
result2 = time3 + time4
print(result2) # 输出 4:10
此代码定义了一个 Time 类,包含
__init__
方法用于初始化小时和分钟,
__add__
方法用于实现时间相加,
__str__
方法用于格式化输出时间。