C语言中的结构体和共用体(联合体)

嵌入式ARM 2020-07-01 00:00

来自:知识小集(微信号:iOS-Tips)

https://kangzubin.com/c-pointer-array/


在 C 语言中,结构体(struct)是一个或多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组织在一个名字之下。由于结构体将一组相关变量看作一个单元而不是各自独立的实体,因此结构体有助于组织复杂的数据,特别是在大型的程序中。

共用体(union),也称为联合体,是用于(在不同时刻)保存不同类型和长度的变量,它提供了一种方式,以在单块存储区中管理不同类型的数据。

今天,我们来介绍一下 C 语言中结构体和共用体的相关概念和使用。

结构体 / struct

结构体的定义

声明一个结构体类型的一般形式为:

struct 结构体名 {
    成员列表
};

其中,成员列表中对各成员都应进行类型声明,即:

类型名 成员名;

例如,我们需要在程序中记录一个学生(student)的数据,包括学号(num)、姓名(name)、性别(sex)、年龄(age)、成绩(score)、地址(addr)等,如下图所示:

如果要表示图中的数据结构,但 C 语言并没有提供这种现成的数据类型,因此我们需要用定义一种结构体类型来表示。

truct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
};

上述定义了一个新的结构体类型 struct student(注意,struct 是声明结构体类型时所必须使用的关键及,不能省略),它向编译系统声明,这是一个“结构体类型”,它包括 num、name、sex、age、score、addr 等不同类型的数据项。

应当说,这里的 struct student 是一个类型名,它与系统提供的标准类型(如 int、char、float、double 等)具有同样的作用,都可以用来定义变量的类型。

结构体变量

前面只是声明了一个结构体类型,它相当于一个模型,但其中并无具体的数据,编译系统对其也不分配实际的内存单元。为了能在程序中使用结构体类型的数据,我们应当定义结构体类型的变量,并在其中存放具体的数据。主要以下 3 中方式定义结构体类型变量:

  • 先声明结构体类型,再定义变量名

结构体类型名 结构体变量名;

例如上面我们已经定义了一个结构体类型 struct student,就可以用它来声明变量:

struct student student1, student2;

定义了 student1 和 student2 为 struct student 类型的变量,它们具有 struct student 类型的结构,后续我们可以对它们进行初始化。

  • 在声明类型的同时定义变量例如:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
} student1, student2;

它的作用与第一种方法相同,即定义了两个 struct student 类型的变量 student1、student2。这种形式的定义的一般形式为:

struct 结构体名 {
    成员列表
} 变量名列表;

  • 直接定义结构体类型变量其省略了结构体名,一般形式为:

struct {
    成员列表
} 变量名列表;

关于结构体类型,需要补充说明一点:

类型与变量是不同的概念,不要混淆。我们只能对变量赋值、存取或运算,而不能对一个类型进行赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。

简单地说,我们可以把“结构体类型”和“结构体变量”理解为是面向对象语言中“类”和“对象”的概念。

此外,结构体里的成员也可以是一个结构体变量。比如我们先声明了一个结构体 struct date

struct date {
    int month;
    int day;
    int year;
};

然后把它应用于声明 struct student 中:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    struct date birthday;
    char addr[30];
} student1, student2;

最后,解释一个在阅读大型开源代码(比如 Objective-C Runtime 源码)时容易产生疑问的点:如下两个结构体 SampleA 和 SampleB 声明的变量在内存上其实是完全一样的,原因是因为结构体本身并不带有任何额外的附加信息:

struct SampleA {
    int a;
    int b;
    int c;
};

struct SampleB {
    int a;
    struct Part1 {
        int b;
    };
    struct Part2 {
        int c;
    };
};

结构体变量的引用

引用结构体变量中成员的方式为:

结构体变量名.成员名

例如,student1.num 表示 student1 变量中 num 成员,我们可以对结构体变量的成员进行赋值:student1.num = 10010;。

如果成员本身又属于一个结构体类型,则要用若干个成员运算符(点号 .),一级一级地找到最低一级的成员,例如:

student1.birthday.month = 9;

另外对结构体变量的成员可以像普通变量一样进行各种运算,也可以用取址运算符 & 引用结构体变量成员的地址,或者引用结构体变量的地址。

结构体变量的初始化

和其他类型变量一样,对结构体变量可以在定义时指定其初始值,用大括号括起来:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    char addr[30];
} a = {10010, "Li Lei"'M', 18, "Beijing Haidian"};

结构体与数组

如果一个数组的元素为结构体类型,则称其为“结构体数组”。结构体数组与之前介绍的数值型数组的不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项。

  • 定义结构体数组

和定义结构体变量的方法类似,只需声明其为数组即可,例如:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
};
struct student stu[3];

以上定义了一个数组 stu,数组有 3 个元素,均为 struct student 类型数据,如下图:

  • 结构体数组的初始化

与其他类型的数组一样,对结构体数组可以初始化,例如:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
} stu[3] = {{10101, "Li Lin", 'M', 18, 87.5, "Beijing"},
            {10102, "Amey", 'M', 17,  92, "Shanghai"},
            {10103, "Bingo", 'F', 20, 100, "Fujian"}};

从上面可以看到,结构体数组的初始化的一般形式是在定义数组的后面加上“={初值表列};”。

结构体数组中各元素在内存中也是连续存放的,如下图:

结构体与指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。

  • 指向结构体变量的指针

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
};
struct student stu1 = {...};
struct student * p;

p = &stu1;

上述代码先声明了 struct student 结构体类型,然后定义一个 struct student 类型的变量 stu1,同时又定义了一个指针变量 p,它指向一个 struct student 类型的数据,最后把结构体变量 stu1 的起始地址赋给指针变量 p,如图所示:

此时可以用 *p 来访问结构体变量 stu1 的值,用 (*p).num来访问 stu 的成员变量。C 语言为了使用方便和直观,定义可以把 (*p).num 改用 p->num 来代替,它表示 p 所指向的结构体变量中的 num 成员。

也就是说,以下 3 种形式等价:

  • 结构体变量.成员名:stu1.num

  • (*指针变量名).成员名:(*p).num

  • 指针变量名->成员名:p->num

  • 指向结构体数组的指针对于结构体数组及其元素也可以用指针变量来指向,例如:

struct student {
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
};

struct student stu[3] = {{10101, "Li Lin", 'M', 18, 87.5, "Beijing"},
                         {10102, "Amey", 'M', 17,  92, "Shanghai"},
                         {10103, "Bingo", 'F', 20, 100, "Fujian"}};
struct student *p = stu;

此时,指针变量 p 指向数组首个元素的地址,即 &stu[0],也就是数组名 stu

结构体指针使用场景

(1)函数参数:用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。

void printStudentInfo(struct student *p);

因为如果我们直接用结构体变量(不是结构体指针)作为实参时,由于采取的是“值传递”的方式,将结构体变量所占用的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。

在函数调用期间,形参也要占用内存单元,这种传递方式将带来较大的时间和空间开销,同时也不利于将在函数执行期间改变形参结构体的值(结果)返回给主调函数,因此一般比较少直接“用结构体变量做实参”,而是改用指针的形式。

(2)链表

链表是一种常见的且很重要的数据结构,一般用于动态地进行存储分配。常见的有单链表和双链表等,一般可以用结构体来表示链表的节点,如下为常见的“单链表”节点的声明:

struct ListNode {
    int val;
    struct ListNode *next;
};

其中,val 表单链表节点的值,next 指针用于指向链表的下一个节点。

例如,面试比较常考察的“反转单链表”的题目:

struct ListNode *reverseList(struct ListNode *head) {
    if (head == NULL) {
       return NULL;
    }
    
    if (head->next == NULL) {
        return head;
    }
    
    struct ListNode *reversedHead = NULL;
    struct ListNode *prevNode = NULL;
    struct ListNode *currentNode = head;
    
    while (currentNode != NULL) {
        struct ListNode *nextNode = currentNode->next;
        if (nextNode == NULL) {
            reversedHead = currentNode;
        }
        
        currentNode->next = prevNode;
        prevNode = currentNode;
        currentNode = nextNode;
    }
    
    return reversedHead;
}

(3)二叉树

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

其中 val 表示二叉树叶子节点的值,left 指向节点的左子树,right 指向右子树。

例如,之前闹得沸沸扬扬的 Google 面试“翻转二叉树”的题目:

struct TreeNode *invertTree(struct TreeNode *root) {
    if (root == NULL) {
        return NULL;
    }
    
    root->left = invertTree(root->left);
    root->right = invertTree(root->right);
    
    struct TreeNode *temp = root->left;
    root->left = root->right;
    root->right = temp;
    
    return root;
}

动态开辟和释放内存空间

前面介绍,链表结构是动态地分配存储的,即在需要时才开辟一个节点的存储单元。那么,怎样动态地开辟和释放存储单元呢?C 语言编译系统的库函数提供了以下相关函数。

  • malloc 函数

void * malloc(unsigned size);

其作用是在内存的动态存储区(堆)中分配一个长度为 size 的连续空间,此函数的返回值是一个指向分配域起始地址的指针(类型为 void *,即空指针类型,使用时可转换为其他指针数据类型)。如果此函数未能成功地执行(例如内存空间不足时),则返回空指针 NULL

使用示例:

int *result = malloc(2 * sizeof(int));
struct ListNode *node = malloc(sizeof(struct ListNode));

上述 result 是一个分配在堆上的长度为 2 的数组,它与 int result[2]; 的区别是后者分配在内存栈区。而 node 是指向一个 struct ListNode 类型的数据(同样已分配在堆上)的起始地址的指针变量。

  • calloc 函数

void * calloc(unsigned n, unsigned size);

其作用是在内存的动态存储区中分配 n 个长度为 size 的连续空间,函数返回一个指向分配域起始地址的指针,如果分配不成功,返回 NULL

  • realloc 函数

void * realloc(void *p, unsigned size);

其作用是将 p 所指向的已分配的动态内存区域的大小重新改为 sizesize 可以比原来分配的空间大或小。该函数返回指向所分配的内存区起始地址的指针,同样,如果分配不成功,返回 NULL

如果传入的 p 为 NULL,则它的效果和 malloc 函数相同,即分配 size 字节的内存空间。

如果传入 size 的值为 0,那么 p 指向的内存空间就会被释放,但是由于没有开辟新的内存空间,所以会返回空指针 NULL,类似于调用 free 函数。

  • free 函数

void free(void *p);

其作用是释放 p 所指向的内存区,使这部分内存区能被其他变量使用,p 一般为调用上述几个函数返回的值。free 函数无返回值。

共用体 / union

有时,我们需要使几种不同类型的变量存放到同一段内存单元中。例如,可以把一个整型变量(2 个字节)、一个字符型变量(1 个字节)、一个实型变量(4 个字节)放在同一开始地址的内存单元中,如下图所示:

以上 3 个变量在内存中占的字节数不同,但都从同一地址开始存放,也就是几个变量相互覆盖。这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构,也称为“联合体”。

共用体变量的定义

定义共用体类型变量的一般形式为:

union 共用体名 {
    成员列表
} 变量

列表;例如:

union data {
    int i;
    char c;
    float f;
} a, b, c;

也可以将类型声明与变量的定义分开:

union data {
    int i;
    char c;
    float f;
};
union data a, b, c;

即先声明一个 union data 类型,再将 a, b, c 定义为 union data 类型。此外,也可以省略共用体名直接定义共用体变量:

union {
    int i;
    char c;
    float f;
} a, b, c;

可以看到,“共用体”与“结构体”的定义形式相似,但它们的含义是不同的:

  • 结构体变量所占的内存长度(字节总数)是各成员占的内存长度之和,每个成员都分别独占其自己的内存单元。
  • 共用体变量所占的内存长度等于最长的成员的长度。例如上述定义的共用体变量 a, b, c 各占 4 个字节(因为其中最长的实型变量占 4 个字节),而不是各占 2+1+4=7 个字节。

共用体变量的引用

与结构体类似,共用体变量中成员的引用方式为:

共用体变量名.成员名

只有先定义了共用体变量才能引用它,而且不能直接引用共用体变量,只能引用共用体变量中的成员。例如,前面定义了共用体变量 a,则:

  • a.i 表示引用共用体变量中的整型变量 i
  • a.c 表示引用共用体变量中的字符型变量 c
  • a.f 表示引用共用体变量中的实型变量 f

但不能只引用共用体变量,例如 printf("%d", a); 是错误的,因为 a 的存储区有好几种类型,分别占不同长度的字节,仅写共用体变量名 a,难以使系统确定究竟输出的哪一个成员的值。

共用体类型数据的特点

在使用共用体类型数据时,应当注意以下一些特点:

  • 同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。也就是说,每一瞬时只有一个成员起作用,其它的成员不起作用,即:共用体中的成员不是同时都存在和起作用的。

  • 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后,原有的成员就失去作用了。例如有如下赋值语句:

a.i = 1;
a.c = 'F';
a.f = 2.5;

在执行完以上 3 条赋值语句后,此时只有 a.f 是有效的,而 a.i 和a.c 已经无意义了。因此在引用共用体变量的成员时,程序员自己必须十分清楚当前存放在共用体变量中的究竟是哪个成员。

  • 共用体变量的地址和它的各成员的地址都是同一地址,例如 &a、&a.i、&a.c、&a.f 都是同一个地址值,其原因是显然的。

  • 不能直接对共用体变量名赋值,也不能企图引用变量名来得到一个值,同时也不能在定义共用体变量时对它初始化。例如,以下这些都是不对的:

union {
    int i;
    char c;
    float f;
} a = {1, 'a', 1.5}; // 不能对共用体初始化
a = 1; // 不能对共用体变量赋值
m = a; // 不能引用共用体变量名以得到一个值

  • 不能把共用体变量作为函数参数,也不能使函数返回共同体类型的变量,但可以使用指向共用体变量的指针(与结构体变量的指针用法类似,不再赘述)。

  • 共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。

共用体总感觉像是计算机发展早期,内存寸土寸金的遗留产物。

总结

本文简要介绍了 C 语言中结构体和共用体的概念及其应用,如有不当之处,欢迎指出。


-END-




推荐阅读



【01】图文并茂,一次搞定C语言结构体内存对齐!(包含完整源码)
【02】结构体内存对齐,这回给你彻底搞会!
【03】RAM较小的MCU必须会这个技巧!结构体内存对齐解析
【04】工程师:这道题80%初学者都没做对!你确定搞懂结构体内存对齐了?
【05】C语言之结构体就这样被攻克了!(绝对值得收藏的文章)


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除
嵌入式ARM 关注这个时代最火的嵌入式ARM,你想知道的都在这里。
评论
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 78浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 166浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 547浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 82浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 202浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 126浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 70浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 108浏览
  • 80,000人到访的国际大展上,艾迈斯欧司朗有哪些亮点?感未来,光无限。近日,在慕尼黑electronica 2024现场,ams OSRAM通过多款创新DEMO展示,以及数场前瞻洞察分享,全面展示自身融合传感器、发射器及集成电路技术,精准捕捉并呈现环境信息的卓越能力。同时,ams OSRAM通过展会期间与客户、用户等行业人士,以及媒体朋友的深度交流,向业界传达其以光电技术为笔、以创新为墨,书写智能未来的深度思考。electronica 2024electronica 2024构建了一个高度国际
    艾迈斯欧司朗 2025-01-16 20:45 507浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 173浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 204浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 188浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 171浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦