嵌入式C语言学习 极速版
define 常量名 常量数据// 定义数组(未初始化)// 包含5个int元素的数组// 定义并初始化// 完全初始化// 自动推断长度为3// 全部初始化为0返回类型 函数名(参数列表) {// 函数体return 返回值;// 非void类型必须返回指针是一个存储内存地址的变量。它指向内存中的某个位置,通过这个地址可以访问或修改该位置的数据。int a = 10;// 在酒店开一个房间(房间
1.常量
程序在运行过程中 我们无法修改的数据 使用常量可以确保数据不会被改变。
1.1字面常量
数字常量 100
字符串常量 "ABCD"
字符常量 'A'
1.2宏定义常量
#define 常量名 常量数据
#define MAX_LEVEL100
2.变量
解释:程序在运行过程中,数据会发生改变的数据容器,就像是可以重复擦写的标签,数值的变化需要一个容器来存,怎么解释这个容器:我们需要向系统申请一个用来存放数据的空间,这个空间像一个盒子,给这个盒子起名(定义数据类型和数据名字,这个名字其实就是这个盒子在整个存储空间的地址),这样我们就可以把数据存放到这个盒子,也可以从盒子中取出数据。
3.数据类型
不同类型的数据需要不同的容器(也就是不同的空间)去存储(整数,小数,文字)。
3.1整型(存放整数)
短整型(short)
整型(int)
长整型(long)
3.2浮点型(存放小数)
单精度(float)
双精度(double)
3.3字符型(存放单个字符)
char great = a;
4.运算符
一张图总结

4.1基本运算符
+ - * /最基本的运算符 但是需要注意两点
1.对于+、-、*、/来说 如果操作符的两个操作数其中一个操作数是小数 则执行小数运算,如果都为整数 则进行整数运算。
2.%的两个操作数必须都为整数,否则会报错。
4.2移位操作符
注意:<<是向左移位、>>是向右移位 移位操作符不能移动负数位

4.3位操作符
&表示都 两个条件都要满足
|表示或 有一个条件不行就不成立
^表示取反 ^的值和&的相反
4.4赋值运算符
赋值运算符和符合运算符 = +=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=
int a = 0;
int b = 8;
a+=b; //相当于a = a+b 所以a=8
a-=b; //相当于a = a-b 因为a=8,a-b为0
//其他运算符同理,这种复合运算符可以使代码更加简洁
4.5单目操作符
! (逻辑反操作)
- (负值)
+ (正值)
& (取地址)
sizeof (操作数的类型长度(以byte为单位))
~ (对数值的二进制位取反)
- (前置后置- -)
++ (前置后置++)
* (解引用操作符)
演示代码
#include <stdio.h>
int main()
{
int a = -10;
int *p = NULL;
printf("%d\n", !2); //逻辑反操作,逻辑上一个值不是真就是假,非0即为真,!就是对一个数进行反操作2是真,!2即为假就是0
printf("%d\n", !0); //0是假,!0为真,就是1
a = -a; //原来的a为-10,-a就是10
p = &a; //&就是取a的地址
printf("%d\n", sizeof(a)); //a的长度就是int类型的长度为4byte
printf("%d\n", sizeof(int)); //int的长度为4byte
printf("%d\n", sizeof a); //sizeof后面跟变量可以不写括号
return 0;
}
//++和--运算符
//前置++和--
#include <stdio.h>
int main()
{
int a = 10;
int x = ++a;
//先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
int y = --a;
//先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
return 0;
}
//后置++和--
#include <stdio.h>
int main()
{
int a = 10;
int x = a++;
//先对a先使用,再增加,这样x的值是10;之后a变成11;
int y = a--;
//先对a先使用,再自减,这样y的值是11;之后a变成10;
return 0;
}
#include <stdio.h>
int main()
{
a = 10;
int* b = &a;
printf("%d",b); //在c语言中我们常常会用到指针,如果不对其进行解引用,那么输出的值是a的地址。
printf("%d",*b); //解引用后值为10
}
int main()
{
float a = 10.3;
printf("%d",(int)a); //在实际中如果某个数我们定义成一个类型,但是输出时又想用另一个类型输出,那么我们就可以对其进行强制类型转换,使其强转为你想要的值,但谨慎使用!!!容易出错!!!
}
#include <stdio.h>
void test1(int arr[])
{
//这里arr被形参接手之后已经是首地址了,所以sizeof(arr)为8(在64位环境下,32位环境为4)
printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
//同上,ch接受过来已经是首地址了,所以地址的大小为8(64位环境下,32位环境为4)
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr)); //整个数组的大小为40
printf("%d\n", sizeof(ch)); //整个数组的大小为10
test1(arr);
test2(ch);
return 0;
}
4.6关系运算符
> >= < <= !=(不等于) ==(等于)关系运算符就是进行比较,没什么太多细节,结果为真返回1,结果为假返回。
4.7逻辑运算符
&&(逻辑与) ||(逻辑或)
int main()
{
printf("%d",1&2); //0,对二进制进行与操作,对应的二进制位都为真,结果为真
printf("%d",1&&2); //1,对数值进行与操作,都为真,结果为真
printf("%d",1|2); //3,对二进制位进行或操作,对应的二进制位只要有一个为真,结果为真
printf("%d",1||2); //1,对数值进行或操作,只要有一方为真,结果为真
}
4.8条件操作符
a ? b : c
int main
{
if(a>10)
b = 5;
else
b = -1;
//等价于
a>10 ? b=5 : b=-1;
}
4.9逗号表达式
(a, b, c, …n)
逗号表达式只不过就是用逗号隔开的表达式 从左到右 依次执行 整个表达式的结果为最后一个表达式的结果 注意一定要用括号括起来。
int main()
{
int a = 1;
int b = 3;
int c = (a++,b++,a+b);
printf("%d",c);
//c = 6 ,从左到右执行返回最右面的表达式
//等价于
//a++;
//b++;
//int c = a+b;
}
4.10下标引用、函数调用和结构成员
[]下标引用操作符 ()函数调用操作符 . 结构体 成员 -> 结构体指针->成员名
4.10.1[]下标引用
[ ] 需要两个操作数:数组名 [ 下标值 ]
int arr[10] = {0}; //定义数组
arr[8] = 8; //用于找到下标
4.10.2()操作数
()操作数最少要有一个函数名 剩下的操作数看形参的数量 : 函数名(形参1,形参2…)
void test()
{
printf("asdfa");
}
void test(int a)
{
printf("%d",a);
}
int main()
{
int a=0;
test(); //一个操作数 test
test(a); //两个操作数 test、a
//以此类推还可以有很多操作数,由形参的数量决定
}
4.10.3访问结构体的操作符
. 和->访问结构体
struct Stu
{
char name[10];
int age;
};
void set_age1(struct Stu stu)
{
stu.age = 18;
}
void set_age2(struct Stu* pStu)
{
pStu->age = 18; //结构成员访问
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu; //结构成员访问
stu.age = 20; //结构成员访问
set_age1(stu);
pStu->age = 20; //结构成员访问
set_age2(pStu);
return 0;
}
5.if语句
5.1基本用法
示例代码
if (条件表达式) {
// 条件为真时执行的代码
}
int age = 18;
if (age >= 18) {
printf("已成年\n");
}
//------------------------------------------------------------------------------
if (条件表达式) {
// 条件为真时执行
} else {
// 条件为假时执行
}
int score = 85;
if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
//-----------------------------------------------------------------------------
if (条件1) {
// 条件1为真时执行
} else if (条件2) {
// 条件2为真时执行
} else {
// 所有条件均不满足时执行
}
int score = 75;
if (score >= 90) {
printf("优秀\n");
} else if (score >= 80) {
printf("良好\n");
} else if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
//------------------------------------------------------------------------------
5.2进阶用法
5.2.1如果代码块只有一行,可以省略 {}
if (条件) printf("条件成立\n");
5.2.2可以在 if 条件中赋值,并检查赋值后的值
int num;
if ((num = get_value()) > 0) { // 赋值并判断
printf("num = %d\n", num);
}
5.2.3组合条件
&&(逻辑与):所有条件必须同时成立。
||(逻辑或):任意一个条件成立即可。
!(逻辑非):取反条件。
int age = 20;
bool is_student = true;
if (age >= 18 && is_student) {
printf("成年学生\n");
}
if (age < 12 || age > 65) {
printf("可享受优惠\n");
}
if (!is_student) {
printf("非学生\n");
}
5.2.4三目运算符(?:)
替代简单 if-else 如果只是简单的条件赋值,可以使用三目运算符
int a = 10, b = 20;
int max = (a > b) ? a : b; // 等效于 if-else
6.switch语句
6.1基本用法
switch (表达式) {
case 常量1:
// 代码块1
break;
case 常量2:
// 代码块2
break;
default:
// 默认代码块(可选)
}
int day = 3;
switch (day) {
case 1: printf("周一\n"); break;
case 2: printf("周二\n"); break;
case 3: printf("周三\n"); break;
default: printf("无效日期\n");
}
6.2进阶用法
6.2.1case 穿透(Fall-through)
故意省略 break 让多个 case 执行同一段代码
int month = 2;
switch (month) {
case 1:
case 3:
case 5:
printf("31天\n"); break;
case 2:
printf("28天\n"); break;
default:
printf("30天\n");
}
6.2.2switch 嵌套
switch (x) {
case 1:
switch (y) {
case 10: printf("x=1, y=10\n"); break;
}
break;
}
7.for循环
7.1基本用法
for (初始化; 条件; 更新) {
// 循环体
}
for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
7.2进阶用法
7.2.1无限循环
for (;;) { // 相当于 while(1)
printf("无限循环\n");
}
7.2.2多变量循环
for (int i = 0, j = 10; i < j; i++, j--) {
printf("i=%d, j=%d\n", i, j);
}
7.2.3遍历数组
int arr[] = {1, 2, 3};
for (int i = 0; i < 3; i++) {
printf("%d ", arr[i]);
}
8.while循环
8.1基本用法
先判断条件,再执行循环体(可能一次都不执行)
while (条件) {
// 循环体
}
int i = 0;
while (i < 5) {
printf("%d ", i++);
}
8.2进阶用法
8.2.1break 和 continue
break:立即退出循环 continue:跳过本次循环,进入下一次。
int i = 0;
while (i < 10) {
i++;
if (i == 5) break; // 当 i=5 时退出循环
if (i % 2 == 0) continue; // 跳过偶数
printf("%d ", i);
}
8.2.2while 读取输入
char ch;
while ((ch = getchar()) != '\n') { // 读取字符直到回车
printf("%c", ch);
}
9.do-while
9.1基本用法
先执行循环体,再判断条件(至少执行一次)
do {
// 循环体
} while (条件);
int i = 0;
do {
printf("%d ", i++);
} while (i < 5);
9.2进阶用法
在宏定义中使用 do-while(0) 可以避免宏展开时的语法错误
#define SAFE_PRINT(msg) do { \
printf("%s\n", msg); \
log_to_file(msg); \
} while (0)
// 调用
if (flag)
SAFE_PRINT("Hello"); // 宏展开后不会因缺少大括号而出错
10.数组
数组是由基本数据类型按照一定规则组成的,称其为构造数据类型。
构造数据类型包括数组,结构体,共用体等,使用构造数据类型可以求解更为复杂的问题。
数组是最基本的构造类型,是相同类型数据的有序集合。
数组中的元素在内存中连续存放,用数组名和下标可以唯一地确定数组元素。
10.1定义与初始化
10.1.1一维数组
// 定义数组(未初始化)
int arr1[5]; // 包含5个int元素的数组
// 定义并初始化
int arr2[3] = {1, 2, 3}; // 完全初始化
int arr3[] = {1, 2, 3}; // 自动推断长度为3
int arr4[5] = {0}; // 全部初始化为0
10.1.2二维数组
#include <stdio.h>
#include <stdlib.h> // 用于动态内存分配
int main() {
// 1. 静态初始化(固定大小)
int static_matrix[3][4] = {
{1, 2, 3, 4}, // 第一行
{5, 6, 7, 8}, // 第二行
{9, 10, 11, 12} // 第三行
};
// 2. 部分初始化(未初始化的元素自动为0)
int partial_matrix[3][4] = {
{1, 2}, // 第一行:1,2,0,0
{5, 6, 7}, // 第二行:5,6,7,0
{9} // 第三行:9,0,0,0
};
// 3. 连续内存初始化(编译器自动填充)
int flat_matrix[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
// 4. 动态分配(运行时确定大小)
int rows = 3, cols = 4;
int **dynamic_matrix = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
dynamic_matrix[i] = (int *)malloc(cols * sizeof(int));
// 可选:初始化动态分配的内存
for (int j = 0; j < cols; j++) {
dynamic_matrix[i][j] = i * cols + j + 1; // 示例数据
}
}
// 打印示例(静态数组)
printf("Static matrix:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%2d ", static_matrix[i][j]);
}
printf("\n");
}
// 释放动态内存
for (int i = 0; i < rows; i++) {
free(dynamic_matrix[i]);
}
free(dynamic_matrix);
return 0;
}
10.2访问数组元素
打印数组元素
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5}; // 定义并初始化数组
int size = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
printf("数组元素为:");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
数组名是元素的首地址
int arr[3] = {1, 2, 3};
int *p = arr; // p指向arr[0]
printf("%d\n", *p); // 输出: 1
数组作为函数参数
void printArray(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
int main() {
int arr[] = {1, 2, 3};
printArray(arr, 3); // 输出: 1 2 3
}
动态数组(堆内存分配)
int *arr = (int *)malloc(5 * sizeof(int)); // 分配5个int的空间
if (arr != NULL) {
arr[0] = 10; // 使用
free(arr); // 释放内存
}
10.3数组的常见操作
10.3.1遍历数组
int arr[] = {1, 2, 3};
for (int i = 0; i < 3; i++) {
printf("%d ", arr[i]);
}
10.3.2排序
void bubbleSort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//冒泡排序
10.3.3查找
int linearSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // 返回下标
}
}
return -1; // 未找到
}
//线性查找
11.函数
C语言中的函数是一段独立的代码块,用于执行特定的任务。函数可以接受输入参数,执行一系列操作,并返回结果。
11.1函数定义
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 非void类型必须返回
}
int add(int a, int b) {
return a + b;
}
11.2函数声明与调用
返回类型 函数名(参数类型列表);
int add(int, int); // 声明
int result = add(3, 5); // 调用
11.3参数的传递
//值传递(默认方式)
void modify(int x) {
x = 10; // 不影响实参
}
//指针传递(地址传递)
void modify(int *x) {
*x = 10; // 修改实参的值
}
//数组参数
void printArray(int arr[], int size) {
// 数组名退化为指针
}
11.4函数的返回值
//基本类型返回
int getValue() {
return 42;
}
//返回指针
int* createArray(int size) {
int *arr = malloc(size * sizeof(int));
return arr;
}
//无返回值(void)
void printHello() {
printf("Hello\n");
}
11.5函数特性
//递归函数
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
//内联函数(C99)
inline int max(int a, int b) {
return a > b ? a : b;
}
// 可变参数函数
#include <stdarg.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
11.6指针函数
//定义函数指针
int (*funcPtr)(int, int); // 指向返回int,接受两个int的函数
//使用函数指针
funcPtr = add; // 指向add函数
int result = funcPtr(3, 5); // 通过指针调用
//回调函数
void process(int (*callback)(int)) {
int result = callback(10);
// 处理结果
}
11.7作用域规则
void func() {
int x = 10; // 局部变量
}
int global = 100; // 全局变量
void func() {
global++; // 可访问
}
void counter() {
static int count = 0; // 只初始化一次(静态变量)
count++;
}
12.指针(C语言灵魂)
12.1什么是指针?
指针是一个存储内存地址的变量。它指向内存中的某个位置,通过这个地址可以访问或修改该位置的数据。
int a = 10; // 在酒店开一个房间(房间号是a),让10先生入住(这个房间是int型单人房)
int *p = &a; // p是一个特殊的遥控器,它存储的是房间a的房卡信息
&:取地址运算符
*:解引用运算符(通过地址访问值)
做个比喻
整个计算机内存就像一个大酒店
每个变量(如
a)就是酒店里的一个房间每个房间都有唯一的门牌号(内存地址)
10就是住在房间a里的客人房间类型
int表示这是单人房(只能住一个整数客人)
p是一个特殊的遥控器
&a操作相当于查询房间a的门牌
int *p = &a;表示:把房间a的门牌号存储到遥控器p里 这个遥控器专门用于开a房间的门当10先生要退房时:用
p遥控器开门让10先生离开当11先生要入住时:用
p遥控器开门让11先生住进去*p = 11; // 用遥控器p开门,让11先生入住现在房间
a里住的是11先生(a的值变为11)
此外,在简单说一下int *p 和*p的分别是什么。
int *p:声明一个指针变量p(它专门用于存储int类型数据的地址)
*p:解引用操作(访问p指向的内存位置的实际值)int a = 10; int *p = &a; printf("%p", p); // 输出a的房间号(地址) printf("%d", *p); // 输出开门取出的值:10 *p = 11; // 用遥控器p开门,让11先生入住
12.2指针三要素
12.2.1指针的类型
int *p; // p的类型是 int*
char *cp; // cp的类型是 char*
double *dp; // dp的类型是 double*
12.2.1指针所指向的类型
指针类型只能指向同一种类型,void* 可以指向任何一种类型。
指针声明 指针类型 指向类型
int *p int* int
char **pp char** char*
int (*func)(void) 函数指针 函数类型
int num = 10;
void *vp = # // 合法
// 但解引用前必须转换类型
printf("%d\n", *(int*)vp);
12.2.1指针的值
指针存储的实际内存地址值,决定了:
指针指向的内存位置
指针是否有效(NULL或野指针)
比如
int num = 10;
printf("%p\n", (void*)&num);
需要注意几点
值 说明 NULL空指针,指向地址0 未初始化值 野指针(危险) 已释放内存地址 悬空指针(危险)
12.3指针的算数运算
数组名是数组的首地址!!!
int arr[3] = {10, 20, 30};
int *ptr = arr;
printf("%d\n", *ptr); // 10
printf("%d\n", *(ptr + 1)); // 20(移动4字节,int大小)
12.4函数指针
int add(int a, int b)
{
return a + b;
}
int (*funcPtr)(int, int) = add; // 函数指针(函数单独内存占用一段空间,把函数的地址赋给函数指针)
printf("%d\n", funcPtr(2, 3)); // 输出: 5
12.5指针的类型转换
指针类型转换不改变内存中的实际数据,只改变编译器解释这些数据的方式
目标类型 *指针名 = (目标类型 *)原指针;
int num = 0x12345678; // 4字节整数
int *ip = #
char *cp = (char*)# // 转换为char指针
printf("%x\n", *ip); // 输出: 12345678
printf("%x\n", *cp); // 输出: 78 (小端序)
注意事项
转换类型 安全性 使用场景 T*→void*安全 泛型编程 void*→T*较安全 恢复具体类型 T*→U*危险 低级内存操作 函数指针转换 非常危险 系统编程 整数指针互转 极端危险 硬件操作
13.结构体
13.1什么是结构体
结构体是C语言中自定义复合数据类型的核心工具,允许将多个不同类型的数据组合成单一实体。它在数据封装、内存管理和系统编程中至关重要。
13.1.1结构体定义
struct Point { // 定义结构体类型
int x; // 成员变量
int y;
}; // 注意分号
13.1.2结构体变量声明
// 方式1:独立声明
struct Point p1;
// 方式2:定义时声明
struct Point {
int x;
int y;
} p2, p3; // 同时声明p2和p3
13.1.3结构体初始化
// 顺序初始化
struct Point p1 = {10, 20};
// 指定成员初始化(C99)
struct Point p2 = {.x = 5, .y = 15};
// 结构体数组初始化
struct Point points[3] = {
{1, 2},
{3, 4},
{5, 6}
};
13.2结构体的基础结构
13.2.1先定义结构体类型,在定义结构体变量
struct student //结构体类型 或 结构体名
{
int num;
char name[20]; //结构体成员
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2; //结构体变量
13.2.2定义结构体的同时定义变量
struct data // 结构体类型 或结构体名
{
int day int month; //结构体成员
int year
}time1,time2; //结构体变量
13.2.3直接定义结构体变量
struct // 结构体类型
{
char name[20];
char sex;
int num; //结构体成员
float score[3]
}person1,person2; //结构体变量
注意事项
只有结构体变量才分配地址,而结构体的定义是不分配空间的
结构体中各成员的定义和之前的变量定义一样,但在定义时也不分配空间
结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错
13.3结构体操作
13.3.1成员访问
struct Student {
char name[20];
int age;
};
struct Student s;
strcpy(s.name, "Alice"); // 使用.访问成员
s.age = 20;
13.3.2 结构体指针
struct Student *ptr = &s;
printf("Name: %s\n", ptr->name); // 使用->访问指针成员
ptr->age = 21;
13.3.3.结构体赋值
struct Point a = {1, 2};
struct Point b = a; // 合法!C语言支持结构体整体复制
13.4结构体的基本用法
13.4.1结构体嵌套
struct Date {
int year;
int month;
int day;
};
struct Person {
char name[20];
struct Date birthday; // 嵌套结构体
};
struct Person alice = {
"Alice",
{2000, 5, 20} // 嵌套初始化
};
13.4.2结构体与函数
// 传值(产生副本)
void printPoint(struct Point p) {
printf("(%d, %d)\n", p.x, p.y);
}
// 传指针(高效)
void movePoint(struct Point *p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
13.4.3结构体包含数组
struct Matrix {
int rows;
int cols;
double data[3][3]; // 固定大小数组
};
13.4.4动态结构体
struct Student *createStudent(const char *name, int age) {
struct Student *s = malloc(sizeof(struct Student));
if (s) {
strncpy(s->name, name, sizeof(s->name)-1);
s->age = age;
}
return s;
}
// 使用后需free()
13.5结构体与共用体(Union)
共用体本质
所有成员共享同一块内存
大小由最大成员决定
同一时间只能使用一个成员
union Data {
int i;
float f;
char str[20];
};
struct Variant {
int type; // 类型标识
union {
int intValue;
float floatValue;
char *stringValue;
} data; // 共用体成员
};
13.6结构体与其他类型对比
特性 结构体(struct) 数组(array) 共用体(union) 成员类型 可以不同 必须相同 可以不同 内存占用 所有成员之和+填充 元素类型×数量 最大成员的大小 同时访问成员 支持 支持 一次只能访问一个成员 主要用途 数据聚合 同质数据集合 类型转换/节省内存
14.内存管理
暂无笔记
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)