探索Java的DNA-JVM字节码深度解析

news2024/11/17 23:33:11

引言

在Java的世界里,JVM(Java虚拟机)是我们程序运行的心脏。而字节码,作为JVM的血液,携带着程序的执行指令。今天,我们将深入探索Java字节码的奥秘,一窥JVM如何将人类可读的代码转化为机器可执行的指令。


一、JVM 知识回顾


JVM是一个可以执行Java字节码的虚拟计算机,它包括类加载器、运行时数据区、执行引擎等核心组件。JVM架构保证了Java程序的平台独立性,实现了“一次编写,到处运行”的理念。

关于Java虚拟机的工作原理、作用和应用场景, 感兴趣的朋友请前往查看:Java虚拟机揭秘-底层驱动力,性能保障!


二、Class文件结构


Class文件是JVM执行字节码的载体,它以8位字节为基础单位的二进制流形式存在。Class文件的结构包括魔数、版本号、常量池、字段表集合、方法表集合等。

在这里插入图片描述


下面以一个例子逐步讲解字节码。

//Test.java
public class Test {
    
    private int a;
    
    public int num() {
        return a + 1;
    }
}

通过执行以下命令, 可以在当前所在路径下生成一个Test.class文件。

javac Test.java

以文本形式打开Test.class文件,内容如下:

cafe babe 0000 003d 0013 0a00 0200 0307
0004 0c00 0500 0601 0010 6a61 7661 2f6c
616e 672f 4f62 6a65 6374 0100 063c 696e
6974 3e01 0003 2829 5609 0008 0009 0700
0a0c 000b 000c 0100 0454 6573 7401 0001
6101 0001 4901 0004 436f 6465 0100 0f4c
696e 654e 756d 6265 7254 6162 6c65 0100
036e 756d 0100 0328 2949 0100 0a53 6f75
7263 6546 696c 6501 0009 5465 7374 2e6a
6176 6100 2100 0800 0200 0000 0100 0200
0b00 0c00 0000 0200 0100 0500 0600 0100
0d00 0000 1d00 0100 0100 0000 052a b700
01b1 0000 0001 000e 0000 0006 0001 0000
0002 0001 000f 0010 0001 000d 0000 001f
0002 0001 0000 0007 2ab4 0007 0460 ac00
0000 0100 0e00 0000 0600 0100 0000 0700
0100 1100 0000 0200 12

  • 文件开头的4个字节(“cafe babe”)称之为 魔数,唯有以"cafe babe"开头的class文件方可被虚拟机所接受,这4个字节就是字节码文件的身份识别。

  • 0000是编译器jdk版本的次版本号0


三、反编译字节码文件


使用 javap 命令反编译 Java 字节码文件是一个查看 .class 文件内部结构和字节码指令的简单方法。

用法: javap <options> <classes>

其中<options>选项包括:

-help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

以下是如何使用 javap 命令的基本步骤:

  • 第一步,编译 Java 源文件: 首先,你需要有一个 .class 文件。如果你有一个 .java 源文件,可以使用 javac 命令将其编译成 .class 文件。例如:
javac Test.java

这将在当前目录下生成一个名为 Test.class 的字节码文件。

在这里插入图片描述


  • 第二步,使用 javap 命令: 打开命令行工具(在 Windows 上是 CMD 或 PowerShell,在 macOS 或 Linux 上是 Terminal),然后使用 javap 命令查看 .class 文件的内容。

    可以使用:

    javap -c Test
    

  • 第三步,查看输出: 执行 javap 命令后,你将看到 .class 文件的详细信息,包括类定义、字段、方法以及它们的字节码指令。

在这里插入图片描述

  • 第四步,输出到文件: 如果你想要将 javap 的输出保存到文件中,可以使用重定向操作符 >
javap -c Test > output.txt

这将把 Test.class 文件的字节码指令输出到 output.txt 文件中。

在这里插入图片描述


请注意,javap 主要用于查看字节码指令和类的结构,而不是将 .class 文件完全反编译回 Java 源代码。

如果你需要将 .class 文件反编译为更接近原始源代码的形式,可能需要使用其他专门的反编译工具。


四、字节码文件.class详细解读


执行以下命令,可查看子节码文件内容:

javap -verbose -p Test.class
  Last modified 2024年5月26日; size 265 bytes
  SHA-256 checksum aeba5b65f486bc4f6ee16ec2073e4fec2053987d53cdaed540343c6230966095
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #8                          // Test
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // Test.a:I
   #8 = Class              #10            // Test
   #9 = NameAndType        #11:#12        // a:I
  #10 = Utf8               Test
  #11 = Utf8               a
  #12 = Utf8               I
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               num
  #16 = Utf8               ()I
  #17 = Utf8               SourceFile
  #18 = Utf8               Test.java
{
  private int a;
    descriptor: I
    flags: (0x0002) ACC_PRIVATE

  public Test();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0

  public int num();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field a:I
         4: iconst_1
         5: iadd
         6: ireturn
      LineNumberTable:
        line 7: 0
}
SourceFile: "Test.java"

以上信息是使用 javap 命令反编译 Test.class 文件后得到的输出结果。它展示了 .class 文件的内部结构和相关信息。


下面是对输出结果的详细解析:

(1)、文件元信息

  • Last modified:文件最后修改时间。

  • size:文件大小。

  • SHA-256 checksum:文件的 SHA-256 校验和。


(2)、编译信息

  • Compiled from "Test.java":表明 Test.class 文件是由 Test.java 源文件编译而来。


(3)、类定义

  • public class Test:定义了一个名为 Test 的公共类。


(4)、版本信息

  • minor version: 0major version: 61:表示这个 .class 文件的 Java 版本信息,主版本号是 61,这对应于 Java 17。


(5)、访问标志

  • flags: (0x0021) ACC_PUBLIC, ACC_SUPER:类的标志,ACC_PUBLIC 表示这个类是公开的,ACC_SUPER 是一个默认标志,表示这个类不是 final 的。


    访问标志的含义如下:

    标志名称标志值含义
    ACC_PUBLIC0x0001是否为Public类型
    ACC_FINAL0x0010是否被声明为final,只有类可以设置
    ACC_SUPER0x0020是否允许使用invokespecial字节码指令的新语义.
    ACC_INTERFACE0x0200标志这是一个接口
    ACC_ABSTRACT0x0400是否为abstract类型,对于接口或者抽象类来说,次标志值为真,其他类型为假
    ACC_SYNTHETIC0x1000标志这个类并非由用户代码产生
    ACC_ANNOTATION0x2000标志这是一个注解
    ACC_ENUM0x4000标志这是一个枚举

(6)、常量池

Constant pool
  • 常量池可以理解成Class文件中的资源仓库,包含了类文件中的各种常量引用,例如方法引用、类名、字段名等。

  • 常量池主要存放的是两大类常量:字面量(Literal)和符号引用(Symbolic References)。

  • 字面量类似于java中的常量概念,如文本字符串,final常量等。

  • 符号引用则属于编译原理方面的概念,包括以下三种:

    • 类和接口的全限定名(Fully Qualified Name)

    • 字段的名称和描述符号(Descriptor)

    • 方法的名称和描述符

JVM是在加载Class文件的时候才进行的动态链接,也就是说这些字段和方法符号引用只有在运行期转换后才能获得真正的内存入口地址。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建或运行时解析并翻译到具体的内存地址中。

例如:

  • #1 = Methodref #2.#3:引用了 java/lang/Object 类的无参构造方法 <init>()V

  • #7 = Fieldref #8.#9:引用了 Test 类中的字段 a


(7)、字段

  • private int a;:定义了一个名为 a 的私有整型字段。

(8)、构造方法

  • public Test();:定义了一个公共的无参构造方法,用于实例化 Test 类的对象。

  • Code:构造方法的字节码指令,这里调用了父类 Object 的构造方法。


    Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 2: 0
    

    code内的主要属性为:

    • stack: 最大操作数栈,JVM运行时会根据这个值来分配栈帧(Frame)中的操作栈深度,此处为1。

    • locals: 局部变量所需的存储空间,单位为Slot, Slot是虚拟机为局部变量分配内存时所使用的最小单位,为4个字节大小。方法参数(包括实例方法中的隐藏参数this),显示异常处理器的参数(try catch中的catch块所定义的异常),方法体中定义的局部变量都需要使用局部变量表来存放。值得一提的是,locals的大小并不一定等于所有局部变量所占的Slot之和,因为局部变量中的Slot是可以重用的。

    • args_size: 方法参数的个数,这里是1,因为每个实例方法都会有一个隐藏参数this.

    • LineNumberTable: 该属性的作用是描述源码行号与字节码行号(字节码偏移量)之间的对应关系。可以使用 -g:none 或-g:lines选项来取消或要求生成这项信息,如果选择不生成LineNumberTable,当程序运行异常时将无法获取到发生异常的源码行号,也无法按照源码的行数来调试程序。


(9)、方法

  • public int num();:定义了一个名为 num 的公共方法,返回类型为 int

  • Codenum 方法的字节码指令,它读取字段 a 的值,加 1,然后返回结果。


  • descriptor: I

类型为I, I即是int类型,关于字节码的类型对应如下:

标识字符含义
B基本类型byte
C基本类型char
D基本类型double
F基本类型float
I基本类型int
J基本类型long
S基本类型short
Z基本类型boolean
V特殊类型void
L对象类型,以分号结尾,如Ljava/lang/Object;

(10)、行号表

  • LineNumberTable:提供了源代码行号和字节码指令之间的映射。


(11)、源文件

  • SourceFile: "Test.java":指示这个 .class 文件是由 Test.java 源文件编译而来的。

这个输出结果提供了 Test.class 文件的详细内部结构,包括字段、方法、访问控制、版本信息等。通过这些信息,可以更好地理解 Java 类的编译过程和字节码的细节。


五、分析try-catch-finally


public class TestCode {
    public int foo() {
        int x;
        try {
            x = 1;
            return x;
        } catch (Exception e) {
            x = 2;
            return x;
        } finally {
            x = 3;
        }
    }
}

执行命令:

javac TestCode.java
javap -verbose -p TestCode.class

内容如下:

  Last modified 2024年5月26日; size 418 bytes
  SHA-256 checksum 0d58e986cce436cf5dd634bcfabb39b75afaddaa863d596c1e874f3571832952
  Compiled from "TestCode.java"
public class TestCode
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #9                          // TestCode
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Class              #8             // java/lang/Exception
   #8 = Utf8               java/lang/Exception
   #9 = Class              #10            // TestCode
  #10 = Utf8               TestCode
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               foo
  #14 = Utf8               ()I
  #15 = Utf8               StackMapTable
  #16 = Class              #17            // java/lang/Throwable
  #17 = Utf8               java/lang/Throwable
  #18 = Utf8               SourceFile
  #19 = Utf8               TestCode.java
{
  public TestCode();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public int foo();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=5, args_size=1
         0: iconst_1
         1: istore_1
         2: iload_1
         3: istore_2
         4: iconst_3
         5: istore_1
         6: iload_2
         7: ireturn
         8: astore_2
         9: iconst_2
        10: istore_1
        11: iload_1
        12: istore_3
        13: iconst_3
        14: istore_1
        15: iload_3
        16: ireturn
        17: astore        4
        19: iconst_3
        20: istore_1
        21: aload         4
        23: athrow
      Exception table:
         from    to  target type
             0     4     8   Class java/lang/Exception
             0     4    17   any
             8    13    17   any
            17    19    17   any
      LineNumberTable:
        line 5: 0
        line 6: 2
        line 11: 4
        line 6: 6
        line 7: 8
        line 8: 9
        line 9: 11
        line 11: 13
        line 9: 15
        line 11: 17
        line 12: 21
      StackMapTable: number_of_entries = 2
        frame_type = 72 /* same_locals_1_stack_item */
          stack = [ class java/lang/Exception ]
        frame_type = 72 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
}
SourceFile: "TestCode.java"

我们重点解读名为 foo 的 Java 方法的字节码信息。

下面是对这个输出的详细解析:

  1. 方法签名
    • public int foo();:定义了一个名为 foo 的公共方法,它返回一个整数值。
  2. 方法描述符
    • descriptor: ()I:表示这个方法没有参数,并返回一个 int 类型的值。
  3. 访问标志
    • flags: (0x0001) ACC_PUBLIC:表示这个方法是公开的。
  4. 字节码指令
    • Code:包含了实际执行的方法体的字节码指令。
    • stack=1, locals=5, args_size=1:表示这个方法在执行时,操作数栈的最大深度是 1,局部变量表的大小是 5(包括 this 指针和方法参数),参数大小是 1(对于实例方法,this 指针算作第一个参数)。
  5. 字节码指令详解
    • iconst_1:将整数 1 推送到栈上。
    • istore_1:将栈顶的整数值存储到局部变量 1 中。
    • iload_1:从局部变量 1 中加载整数值到栈上。
    • istore_2:将栈顶的整数值存储到局部变量 2 中。
    • iconst_3:将整数 3 推送到栈上。
    • istore_1:将栈顶的整数值存储到局部变量 1 中。
    • iload_2:从局部变量 2 中加载整数值到栈上。
    • ireturn:将栈顶的整数值作为返回值结束方法。
    • astore_2:将栈顶的引用类型值存储到局部变量 2 中。
    • iconst_2istore_1istore_3aloadathrow:这些指令涉及到异常处理,athrow 指令会抛出异常。
  6. 异常表
    • Exception table:列出了方法中可能抛出的异常及其处理程序的位置。
    • fromtotargettype:分别表示异常发生的起始指令、结束指令、跳转目标指令和异常类型。
  7. 行号表
    • LineNumberTable:提供了源代码行号和字节码指令之间的映射,方便调试。
  8. StackMapTable
    • StackMapTable:在 JDK 7 及以后版本中,用于替代之前的 Exceptions 属性和 LineNumberTable,提供了更详细的栈映射信息,用于支持新的异常表和行号信息。
  9. 源文件
    • SourceFile:指示这个 .class 文件是由哪个 .java 源文件编译而来的。

这个输出结果提供了 foo 方法的字节码指令和相关元信息,包括方法的访问权限、返回类型、局部变量和操作数栈的使用情况、异常处理以及源代码行号映射等。通过这些信息,可以深入理解 Java 方法的执行细节和异常处理机制。


六、结语

字节码不仅支持Java语言,还支持所有编译到字节码的JVM语言,如Groovy、Scala、Kotlin等。此外,字节码层面的优化可以显著提高程序性能。

字节码是Java程序的灵魂,掌握了字节码,就掌握了程序性能的钥匙。本文深入探讨了Java字节码的内部结构和工作原理,然而,字节码的世界远比我们所见的要深邃。

在下一篇文章中,我们将揭开JVM调优的神秘面纱,探索如何通过字节码优化让Java程序运行如飞。敬请期待!


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

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

相关文章

【香橙派AIpro】开箱测评

1.板子开箱 哟&#xff0c;看起来还不错哦&#xff01;&#xff01;&#xff01; 收货清单&#xff1a; 主板*1 1.5m数据线*1 充电头*1 1.1.充电头 近65W的充电头&#xff0c;不错不错。 1.2.主板 1.2.1.上面 哇噢&#xff0c;还送了2.4/5G的WiFi和蓝牙天线。 emm&#xf…

【NumPy】关于numpy.argsort()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

计算机专业必考之计算机指令设计格式

计算机指令设计格式 例题&#xff1a; 1.设相对寻址的转移指令占3个字节&#xff0c;第一字节为操作码&#xff0c;第二&#xff0c;第三字节为相对偏移量&#xff0c; 数据在存储器以低地址为字地址的存放方式。 每当CPU从存储器取出一个字节时候&#xff0c;自动完成&…

通过Zerossl给IP申请免费SSL证书, 实现https ip访问

参考通过Zerossl给IP申请免费SSL证书 | LogDicthttps://www.logdict.com/archives/tong-guo-zerosslgei-ipshen-qing-mian-fei-sslzheng-shu

【Linux-LCD 驱动】

Linux-LCD 驱动 ■ Framebuffer 简称 fb■ LCD 驱动程序编写■ 1、LCD 屏幕 IO 配置■ 2、LCD 屏幕参数节点信息修改■ 3、LCD 屏幕背光节点信息■ 4、使能 Linux logo 显示 ■ 设置 LCD 作为终端控制台■ 1、设置 uboot 中的 bootargs■ 2、修改/etc/inittab 文件 ■ LCD 背光…

亚马逊高效广告打法及数据优化,亚马逊高阶广告打法课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89342733 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-亚马逊的广告漏斗和A9算法的升级变化.mp4 002.2-流量入口解析和广告的曝光机制.mp4 003.3-标签理论 .mp4 004.4-不同广告类…

小程序内使用路由

一:使用组件 1)创建组件 2)在需要的页面的json/app.json可实现局部使用和全局使用 在局部的话,对象内第一层,window配置也是第一层,而在全局配置也是在第一层,window在window对象内.第二层.内部执行遍历不一样. 3)页面使用 上述所写可实现在页面内使用组件.效果是页面内可以将…

预热 618,编程好书推荐——提升你的代码力

文章目录 &#x1f4cb;前言&#x1f3af;编程好书推荐&#x1f4d8; Java领域的经典之作&#x1f40d; Python学习者的宝典&#x1f310; 前端开发者的权威指南&#x1f512; 并发编程的艺术&#x1f916; JVM的深入理解&#x1f3d7; 构建自己的编程语言&#x1f9e0; 编程智…

SolidWorks教育版 学生使用的优势

在工程技术领域的学习中&#xff0c;计算机辅助设计软件&#xff08;CAD&#xff09;如SolidWorks已经成为学生掌握专业知识和技能的必要工具。SolidWorks教育版作为专为教育机构和学生设计的版本&#xff0c;不仅提供了与商业版相同的强大功能&#xff0c;还为学生带来了诸多独…

传输层安全性 (TLS)

传输层安全 (TLS) 旨在提供传输层的安全性。TLS 源自称为安全套接字层 (SSL)的安全协议。 TLS 确保任何第三方都无法窃听或篡改任何消息。 TLS 有几个好处&#xff1a; ● 加密&#xff1a; TLS/SSL 可以帮助使用加密来保护传输的数据。 ● 互操作性&#xff1a; TLS/S…

利用audacity和ffmpeg制作测试音频文件

最近要用SIPP测试一个场景&#xff0c;需要发送双声道/16K采样率/16bit量化的PCM流&#xff0c;但是下载的素材往往不能满足参数要求。那么就自己制作。 首先下载mp3文件&#xff0c;并用audacity打开。 接下来&#xff0c;点击菜单栏中轨道-重采样&#xff0c;将采样频率设为1…

备战秋招c++ 【持续更新】

T1 牛牛的快递 原题链接&#xff1a;牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目类型&#xff1a;模拟 审题&确定思路&#xff1a; 1、超过1kg和不足1kg有两种不同收费方案 ---- 起步价问题 2、超出部分不足1kg的按1kg计算 ----- 向上取整 3、向上取整的实现思路…

运维笔记.Docker镜像分层原理

运维专题 Docker镜像原理 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/artic…

陈丽:人工智能赋能教育创新发展

5月20日&#xff0c;在顾明远先生莅临科大讯飞考察指导高端咨询会暨“人工智能与未来教育”的主题研讨会上&#xff0c;北京师范大学原副校长、中国教育技术协会副会长陈丽教授作了题为《人工智能赋能教育创新发展》的主旨报告。 &#xff08;以下内容根据陈丽教授在研讨会上的…

Python | Leetcode Python题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; class Solution:def connect(self, root: Node) -> Node:if not root:return root# 从根节点开始leftmost rootwhile leftmost.left:# 遍历这一层节点组织成的链表&#xff0c;为下一层的节点更新 next 指针head leftmostwhile head:#…

C++习题(1)

一、题目描述&#xff1a; 二、代码展示&#xff1a; #include <iostream> #include <iomanip> using namespace std; struct Student{char name[20];int id;int age;float score; }; int main() {int n;cin>>n;Student student[n];float sum0.0;for(int i0…

Ubuntu22.04之扩展并挂载4T硬盘(二百三十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

第18章-综合以上功能 基于stm32的智能小车(远程控制、避障、循迹) 基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图

这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能 18-按键和app按钮切换功能 根据上面介绍&#xff0c;我们的模式可…

ADS基础教程15 - 设计加密保护IP

设计加密保护IP 一、引言二、IP的生成与调用1.IP生成2.IP的调用 一、引言 介绍如何ADS中如何对设计好的原理图进行加密形成IP&#xff0c;然偶进行调用的过程。 二、IP的生成与调用 1.IP生成 (1)选择一个已经调试好的原理图&#xff0c;在菜单栏中选择Tools–>Encode De…

Aws CodeCommit代码仓储库

1 创建IAM用户 IAM创建admin用户&#xff0c;增加AWSCodeCommitFullAccess权限 2 创建存储库 CodePipeline -> CodeCommit -> 存储库 创建存储库 3 SSH 1) window环境 3.1.1 上载SSH公有秘钥 生成SSH秘钥ID 3.1.2 编辑本地 ~/.ssh 目录中名为“config”的 SSH 配置文…