关于基于lvgl库做的注册登录功能的代码步骤:

以下是完整的文件拆分和代码存放说明,按功能模块化划分,方便工程管理:

一、需要创建的文件清单
文件名 作用 类型 
main.c 程序入口,初始化硬件和LVGL 源文件 
ui.h 声明界面相关函数 头文件 
ui.c 实现登录、注册、主页面的UI 源文件 
user_data.h 声明用户数据处理函数 头文件 
user_data.c 实现注册/登录的文件读写逻辑 源文件 

二、各文件代码及存放位置

1. main.c(工程入口)存放内容:主函数,初始化硬件、LVGL,启动界面

#include "lvgl/lvgl.h"
#include "ui.h"   // 包含界面函数声明
#include "user_data.h"  // 包含用户数据处理声明// 硬件初始化(需根据GEC6818实际驱动实现)
static void hardware_init(void) {// 此处添加LCD屏幕、触摸驱动的初始化代码// 例如:打开LCD设备、设置分辨率、初始化触摸输入等
}int main(void) {// 1. 初始化硬件hardware_init();// 2. 初始化LVGLlv_init();lv_port_disp_init();  // 显示接口初始化(适配GEC6818 LCD)lv_port_indev_init(); // 输入设备初始化(适配触摸)// 3. 初始化用户数据(如检查存储文件是否存在)// (可选,user_data.c中若有初始化逻辑可在此调用)// 4. 显示初始界面(登录页)create_login_ui();// 5. LVGL主循环while (1) {lv_task_handler();  // 处理LVGL任务usleep(5000);       // 5ms延迟}return 0;
}


2. ui.h(界面函数声明)存放内容:声明所有界面创建和回调函数

#ifndef UI_H
#define UI_H#include "lvgl/lvgl.h"// 登录界面
void create_login_ui(void);// 注册界面
void create_reg_ui(void);// 主页面(登录成功后显示)
void switch_to_main_page(lv_timer_t *t);// 注册成功后返回登录页
void back_to_login(lv_timer_t *t);#endif // UI_H


3. ui.c(界面实现)存放内容:登录/注册/主页面的LVGL组件创建,按钮回调逻辑

#include "ui.h"
#include "user_data.h"  // 调用注册/登录函数// 登录界面输入缓存
static char username[32] = "";
static char password[32] = "";// 注册界面输入缓存
static char reg_username[32] = "";
static char reg_password[32] = "";// 登录界面创建
void create_login_ui(void) {// 清空当前界面lv_obj_clean(lv_scr_act());// 1. 创建主页面容器lv_obj_t *page = lv_obj_create(lv_scr_act());lv_obj_set_size(page, LV_HOR_RES, LV_VER_RES);// 2. 账号输入框lv_obj_t *user_label = lv_label_create(page);lv_label_set_text(user_label, "账号:");lv_obj_align(user_label, LV_ALIGN_TOP_LEFT, 50, 100);lv_obj_t *user_ta = lv_textarea_create(page);lv_textarea_set_placeholder_text(user_ta, "请输入账号");lv_textarea_set_max_length(user_ta, 31);lv_obj_set_size(user_ta, 200, 50);lv_obj_align_to(user_ta, user_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(user_ta, username);// 3. 密码输入框lv_obj_t *pwd_label = lv_label_create(page);lv_label_set_text(pwd_label, "密码:");lv_obj_align(pwd_label, LV_ALIGN_TOP_LEFT, 50, 180);lv_obj_t *pwd_ta = lv_textarea_create(page);lv_textarea_set_placeholder_text(pwd_ta, "请输入密码");lv_textarea_set_password_mode(pwd_ta, true);lv_textarea_set_max_length(pwd_ta, 31);lv_obj_set_size(pwd_ta, 200, 50);lv_obj_align_to(pwd_ta, pwd_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(pwd_ta, password);// 4. 登录按钮及回调lv_obj_t *login_btn = lv_btn_create(page);lv_obj_set_size(login_btn, 100, 40);lv_obj_align(login_btn, LV_ALIGN_TOP_MID, -60, 280);lv_obj_t *login_btn_label = lv_label_create(login_btn);lv_label_set_text(login_btn_label, "登录");lv_obj_add_event_cb(login_btn, login_btn_cb, LV_EVENT_CLICKED, NULL);// 5. 注册按钮(跳转到注册界面)lv_obj_t *to_reg_btn = lv_btn_create(page);lv_obj_set_size(to_reg_btn, 100, 40);lv_obj_align(to_reg_btn, LV_ALIGN_TOP_MID, 60, 280);lv_obj_t *to_reg_label = lv_label_create(to_reg_btn);lv_label_set_text(to_reg_label, "注册");lv_obj_add_event_cb(to_reg_btn, to_reg_cb, LV_EVENT_CLICKED, NULL);
}// 注册界面创建
void create_reg_ui(void) {lv_obj_clean(lv_scr_act());  // 清空当前界面// 1. 标题lv_obj_t *title = lv_label_create(lv_scr_act());lv_label_set_text(title, "用户注册");lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 50);// 2. 注册账号输入框lv_obj_t *reg_user_label = lv_label_create(lv_scr_act());lv_label_set_text(reg_user_label, "新账号:");lv_obj_align(reg_user_label, LV_ALIGN_TOP_LEFT, 50, 100);lv_obj_t *reg_user_ta = lv_textarea_create(lv_scr_act());lv_textarea_set_placeholder_text(reg_user_ta, "请设置账号");lv_textarea_set_max_length(reg_user_ta, 31);lv_obj_set_size(reg_user_ta, 200, 50);lv_obj_align_to(reg_user_ta, reg_user_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(reg_user_ta, reg_username);// 3. 注册密码输入框lv_obj_t *reg_pwd_label = lv_label_create(lv_scr_act());lv_label_set_text(reg_pwd_label, "新密码:");lv_obj_align(reg_pwd_label, LV_ALIGN_TOP_LEFT, 50, 180);lv_obj_t *reg_pwd_ta = lv_textarea_create(lv_scr_act());lv_textarea_set_placeholder_text(reg_pwd_ta, "请设置密码");lv_textarea_set_password_mode(reg_pwd_ta, true);lv_textarea_set_max_length(reg_pwd_ta, 31);lv_obj_set_size(reg_pwd_ta, 200, 50);lv_obj_align_to(reg_pwd_ta, reg_pwd_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(reg_pwd_ta, reg_password);// 4. 注册按钮及回调lv_obj_t *reg_btn = lv_btn_create(lv_scr_act());lv_obj_set_size(reg_btn, 100, 40);lv_obj_align(reg_btn, LV_ALIGN_TOP_MID, -60, 280);lv_obj_t *reg_btn_label = lv_label_create(reg_btn);lv_label_set_text(reg_btn_label, "注册");lv_obj_add_event_cb(reg_btn, reg_btn_cb, LV_EVENT_CLICKED, NULL);// 5. 返回登录按钮lv_obj_t *back_btn = lv_btn_create(lv_scr_act());lv_obj_set_size(back_btn, 100, 40);lv_obj_align(back_btn, LV_ALIGN_TOP_MID, 60, 280);lv_obj_t *back_btn_label = lv_label_create(back_btn);lv_label_set_text(back_btn_label, "返回登录");lv_obj_add_event_cb(back_btn, back_to_login_cb, LV_EVENT_CLICKED, NULL);
}// 登录按钮回调
static void login_btn_cb(lv_event_t *e) {// 获取输入框内容lv_obj_t *user_ta = lv_obj_get_child(lv_scr_act(), 1);  // 账号输入框lv_obj_t *pwd_ta = lv_obj_get_child(lv_scr_act(), 3);   // 密码输入框const char *user = lv_textarea_get_text(user_ta);const char *pwd = lv_textarea_get_text(pwd_ta);// 调用登录验证函数(来自user_data.c)int ret = login_user(user, pwd);lv_obj_t *msg;if (ret == 0) {msg = lv_msgbox_create(NULL, "提示", "登录成功!", NULL, false);lv_timer_create(switch_to_main_page, 1500, NULL);  // 跳转主页面} else if (ret == -1) {msg = lv_msgbox_create(NULL, "提示", "暂无注册用户,请先注册", NULL, false);} else {msg = lv_msgbox_create(NULL, "提示", "账号或密码错误", NULL, false);}lv_obj_center(msg);
}// 注册按钮回调
static void reg_btn_cb(lv_event_t *e) {// 获取注册输入框内容lv_obj_t *reg_user_ta = lv_obj_get_child(lv_scr_act(), 1);  // 新账号输入框lv_obj_t *reg_pwd_ta = lv_obj_get_child(lv_scr_act(), 3);   // 新密码输入框const char *user = lv_textarea_get_text(reg_user_ta);const char *pwd = lv_textarea_get_text(reg_pwd_ta);// 调用注册函数(来自user_data.c)int ret = register_user(user, pwd);lv_obj_t *msg;if (ret == 0) {msg = lv_msgbox_create(NULL, "提示", "注册成功!", NULL, false);lv_timer_create(back_to_login, 1500, NULL);  // 返回登录页} else if (ret == -1) {msg = lv_msgbox_create(NULL, "提示", "账号或密码不能为空", NULL, false);} else if (ret == -2) {msg = lv_msgbox_create(NULL, "提示", "账号已存在", NULL, false);} else {msg = lv_msgbox_create(NULL, "提示", "注册失败", NULL, false);}lv_obj_center(msg);
}// 跳转到注册界面的回调
static void to_reg_cb(lv_event_t *e) {create_reg_ui();
}// 返回登录界面的回调
static void back_to_login_cb(lv_event_t *e) {create_login_ui();
}// 登录成功后跳转主页面
void switch_to_main_page(lv_timer_t *t) {lv_obj_clean(lv_scr_act());lv_obj_t *main_label = lv_label_create(lv_scr_act());lv_label_set_text(main_label, "欢迎进入主页面!");lv_obj_center(main_label);
}// 注册成功后返回登录页
void back_to_login(lv_timer_t *t) {create_login_ui();
}


4. user_data.h(用户数据函数声明)存放内容:声明注册、登录、账号检查等函数

#ifndef USER_DATA_H
#define USER_DATA_H#include <stdio.h>// 注册用户(返回0成功,-1空输入,-2账号已存在,-3文件错误)
int register_user(const char *username, const char *password);// 登录验证(返回0成功,-1无注册用户,-2账号密码错误)
int login_user(const char *username, const char *password);#endif // USER_DATA_H


5. user_data.c(用户数据处理)存放内容:文件读写逻辑,实现注册和登录的核心验证

#include "user_data.h"
#include <string.h>// 存储用户信息的文件路径
#define USER_FILE "users.txt"// 检查账号是否已存在
static int is_username_exist(const char *username) {FILE *fp = fopen(USER_FILE, "r");if (!fp) return 0;  // 文件不存在,无重复char line[128], u[32];while (fgets(line, sizeof(line), fp)) {if (sscanf(line, "%31[^:]", u) == 1 && strcmp(u, username) == 0) {fclose(fp);return 1;  // 账号已存在}}fclose(fp);return 0;
}// 注册函数:写入文件
int register_user(const char *username, const char *password) {// 检查输入合法性if (strlen(username) == 0 || strlen(password) == 0) return -1;if (is_username_exist(username)) return -2;// 写入文件(追加模式)FILE *fp = fopen(USER_FILE, "a");if (!fp) return -3;fprintf(fp, "%s:%s\n", username, password);  // 实际需加密存储fclose(fp);return 0;
}// 登录函数:读取文件比对
int login_user(const char *username, const char *password) {FILE *fp = fopen(USER_FILE, "r");if (!fp) return -1;  // 无注册用户char line[128], u[32], p[32];while (fgets(line, sizeof(line), fp)) {if (sscanf(line, "%31[^:]:%31s", u, p) == 2) {if (strcmp(u, username) == 0 && strcmp(p, password) == 0) {fclose(fp);return 0;  // 登录成功}}}fclose(fp);return -2;  // 账号或密码错误
}


三、工程文件结构
project/
├── main.c          # 主程序入口
├── ui.h            # 界面函数声明
├── ui.c            # 登录/注册界面实现
├── user_data.h     # 数据处理函数声明
├── user_data.c     # 注册/登录文件读写逻辑
└── Makefile        # 编译配置(需自行编写,链接LVGL库)
四、编译说明

• 编译时需链接LVGL库(-llvgl),确保GEC6818的交叉编译环境正确配置。

• 运行后会在程序目录自动生成users.txt文件,存储注册的账号密码。

按此结构存放代码,可实现模块化管理,方便后续修改界面或数据存储逻辑。


如果你的交叉编译工具链是 arm-linux-gcc(而非 arm-linux-gnueabihf-gcc),只需调整 Makefile 中的工具链和编译选项即可。以下是适配 arm-linux-gcc 的版本,可直接使用:适配 arm-linux-gcc 的 Makefile

# 交叉编译工具链(使用arm-linux-gcc)
CC = arm-linux-gcc# LVGL库路径(替换为你的LVGL实际路径)
LVGL_DIR = /path/to/your/lvgl# 源文件列表
SRCS = main.c ui.c user_data.c# 目标文件
OBJS = $(SRCS:.c=.o)# 生成的可执行文件名
TARGET = login_demo# 编译选项(适配arm-linux-gcc,无需硬浮点参数)
CFLAGS = -I. \-I$(LVGL_DIR) \-I$(LVGL_DIR)/src \-I$(LVGL_DIR)/src/core \-I$(LVGL_DIR)/src/hal \-I$(LVGL_DIR)/src/widgets \-O2 -Wall -Wextra \-mlittle-endian \-marm \-mcpu=arm926ej-s  # GEC6818若基于ARM9架构,用此参数;若为A53,可保留-mcpu=cortex-a53# 链接选项(链接LVGL库和系统库)
LDFLAGS = -L$(LVGL_DIR)/build/lib \  # LVGL库的编译输出路径-llvgl \                  # 链接LVGL库-lm -lpthread -ldl        # 系统库(数学库、线程库等)# 默认目标:编译生成可执行文件
all: $(TARGET)# 链接目标文件
$(TARGET): $(OBJS)$(CC) $(OBJS) -o $@ $(LDFLAGS)@echo "编译完成:生成可执行文件 $(TARGET)"# 编译.c文件为.o文件
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@# 清理编译产物
clean:rm -f $(OBJS) $(TARGET)@echo "清理完成".PHONY: all clean


关键调整说明

1. 工具链修改:将 CC 改为 arm-linux-gcc,匹配你的工具链。

2. 架构参数:

◦ 若GEC6818基于 ARM9 架构(部分版本),使用 -mcpu=arm926ej-s。

◦ 若基于 Cortex-A53 架构,保留 -mcpu=cortex-a53 即可。

3. 去除硬浮点参数:arm-linux-gcc 通常不默认支持 neon-vfpv4 等硬浮点选项,因此删除 -mfpu=neon-vfpv4 和 -mfloat-abi=hard。

使用方法

1. 替换 LVGL_DIR 为你的LVGL库实际路径(例如 ~/lvgl)。

2. 终端进入工程目录,执行 make 编译,生成 login_demo。

3. 传输到开发板后,执行 chmod +x login_demo 赋予权限,再运行 ./login_demo。

如果编译时出现架构不匹配的错误,可尝试删除 -mcpu=xxx 选项,或根据开发板CPU型号调整。


如果直接用 arm-linux-gcc 命令编译(不通过 Makefile),可以执行以下完整命令(需根据你的实际路径调整):

arm-linux-gcc main.c ui.c user_data.c -o login_demo \
-I/path/to/your/lvgl \
-I/path/to/your/lvgl/src \
-I/path/to/your/lvgl/src/core \
-I/path/to/your/lvgl/src/hal \
-I/path/to/your/lvgl/src/widgets \
-L/path/to/your/lvgl/build/lib \
-llvgl -lm -lpthread -ldl \
-O2 -Wall -mlittle-endian -marm -mcpu=arm926ej-s


命令说明(按顺序):

1. 编译源文件:main.c ui.c user_data.c 是工程的所有源文件。

2. 指定输出文件名:-o login_demo 表示生成名为 login_demo 的可执行文件。

3. LVGL头文件路径:-I/path/to/your/lvgl 及后续 -I 选项,替换为你的LVGL库实际路径(需包含所有LVGL的头文件目录)。

4. LVGL库路径:-L/path/to/your/lvgl/build/lib 替换为LVGL库编译后的输出目录(包含 liblvgl.a 或 liblvgl.so)。

5. 链接库:-llvgl 链接LVGL库;-lm -lpthread -ldl 链接系统必要的数学库、线程库等。

6. 编译选项:-O2 优化编译;-Wall 显示警告;-mlittle-endian -marm -mcpu=arm926ej-s 适配GEC6818架构(若为A53,可将 arm926ej-s 改为 cortex-a53)。

使用步骤:

1. 打开终端,进入存放 main.c、ui.c、user_data.c 的工程目录。

2. 将上述命令中的 /path/to/your/lvgl 替换为你的LVGL库实际路径(例如 ~/lvgl-8.3)。

3. 粘贴并执行命令,编译成功后会生成 login_demo 文件。

4. 传输到GEC6818开发板,执行 chmod +x login_demo 后,运行 ./login_demo 即可。

如果编译报错“找不到头文件”或“找不到库”,检查路径是否正确;若报架构错误,调整 -mcpu 参数即可。

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

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

相关文章

RAII机制以及在ROS的NodeHandler中的实现

好的&#xff0c;这是一个非常核心且优秀的设计问题。我们来分两步详细解析&#xff1a;先彻底搞懂什么是 RAII&#xff0c;然后再看 ros::NodeHandle 是如何巧妙地运用这一机制的。1. 什么是 RAII 机制&#xff1f; RAII 是 “Resource Acquisition Is Initialization” 的缩写…

Linux LVS集群技术

LVS集群概述1、集群概念1.1、介绍集群是指多台服务器集中在一起&#xff0c;实现同一业务&#xff0c;可以视为一台计算机。多台服务器组成的一组计算机&#xff0c;作为一个整体存在&#xff0c;向用户提供一组网络资源&#xff0c;这些单个的服务器就是集群的节点。特点&…

spring-ai-alibaba如何上传文件并解析

问题引出 在我们日常使用大模型时&#xff0c;有一类典型的应用场景&#xff0c;就是将文件发送给大模型&#xff0c;然后由大模型进行解析&#xff0c;提炼总结等&#xff0c;这一类功能在官方app中较为常见&#xff0c;但是在很多模型的api中都不支持&#xff0c;那如何使用…

「双容器嵌套布局法」:打造清晰层级的网页架构设计

一、命名与核心概念 “双容器嵌套布局法”&#xff0c;核心是通过两层容器嵌套构建网页结构&#xff1a;外层容器负责控制布局的“宏观约束”&#xff08;如页面最大宽度、背景色等&#xff09;&#xff0c;内层容器聚焦“微观排版”&#xff08;内容居中、内边距调整、红色内容…

基于深度学习的自然语言处理:构建情感分析模型

前言 自然语言处理&#xff08;NLP&#xff09;是人工智能领域中一个非常活跃的研究方向&#xff0c;它致力于使计算机能够理解和生成人类语言。情感分析&#xff08;Sentiment Analysis&#xff09;是NLP中的一个重要应用&#xff0c;其目标是从文本中识别和提取情感倾向&…

JWT原理及利用手法

JWT 原理 JSON Web Token (JWT) 是一种开放的行业标准&#xff0c;用于在系统之间以 JSON 对象的形式安全地传输信息。这些信息经过数字签名&#xff0c;因此可以被验证和信任。其常用于身份验证、会话管理和访问控制机制中传递用户信息。 与传统的会话令牌相比&#xff0c;JWT…

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_睡眠记录日历示例(CalendarView01_30)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录DeepS…

git的diff命令、Config和.gitignore文件

diff命令&#xff1a;比较git diff xxx&#xff1a;工作目录 vs 暂存区&#xff08;比较现在修改之后的工作区和暂存区的内容&#xff09;git diff --cached xxx&#xff1a;暂存区 vs Git仓库&#xff08;现在暂存区内容和最一开始提交的文件内容的比较&#xff09;git diff H…

Linux中的LVS集群技术

一、实验环境&#xff08;RHEL 9&#xff09;1、NAT模式的实验环境主机名IP地址网关网络适配器功能角色client172.25.254.111/24&#xff08;NAT模式的接口&#xff09;172.25.254.2NAT模式客户机lvs172.25.254.100/24&#xff08;NAT模式的接口&#xff09;192.168.0.100/24&a…

【数据结构】「队列」(顺序队列、链式队列、双端队列)

- 第 112篇 - Date: 2025 - 07 - 20 Author: 郑龙浩&#xff08;仟墨&#xff09; 文章目录队列&#xff08;Queue&#xff09;1 基本介绍1.1 定义1.2 栈 与 队列的区别1.3 重要术语2 基本操作3 顺序队列(循环版本)两种版本两种版本区别版本1.1 - rear指向队尾后边 且 无 size …

Java行为型模式---解释器模式

解释器模式基础概念解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是定义一个语言的文法表示&#xff0c;并定义一个解释器&#xff0c;使用该解释器来解释语言中的句子。这种模式将语法解释的责任分开&#xff0c;使得语法…

[spring6: PointcutAdvisor MethodInterceptor]-简单介绍

Advice Advice 是 AOP 联盟中所有增强&#xff08;通知&#xff09;类型的标记接口&#xff0c;表示可以被织入目标对象的横切逻辑&#xff0c;例如前置通知、后置通知、异常通知、拦截器等。 package org.aopalliance.aop;public interface Advice {}BeforeAdvice 前置通知的标…

地图定位与导航

定位 1.先申请地址权限(大致位置精准位置) module.json5文件 "requestPermissions": [{"name": "ohos.permission.INTERNET" },{"name": "ohos.permission.LOCATION","reason": "$string:app_name",&qu…

【数据结构】揭秘二叉树与堆--用C语言实现堆

文章目录1.树1.1.树的概念1.2.树的结构1.3.树的相关术语2.二叉树2.1.二叉树的概念2.2.特殊的二叉树2.2.1.满二叉树2.2.2.完全二叉树2.3.二叉树的特性2.4.二叉树的存储结构2.4.1.顺序结构2.4.2.链式结构3.堆3.1.堆的概念3.2.堆的实现3.2.1.堆结构的定义3.2.2.堆的初始化3.2.3.堆…

区间树:多维数据的高效查询

区间树&#xff1a;多维数据的高效查询 大家好&#xff0c;今天我们来探讨一个在计算机科学中非常有趣且实用的数据结构——区间树。想象一下&#xff0c;你是一位城市规划师&#xff0c;需要快速找出某个区域内所有的医院、学校或商场。或者你是一位游戏开发者&#xff0c;需要…

SQL 魔法:LEFT JOIN 与 MAX 的奇妙组合

一、引言 在数据库操作的领域中&#xff0c;数据的关联与聚合处理是核心任务之一。LEFT JOIN作为一种常用的连接方式&#xff0c;能够将左表中的所有记录与右表中满足连接条件的记录进行关联&#xff0c;即便右表中没有匹配的记录&#xff0c;左表的记录也会被保留&#xff0c;…

手写tomcat

package com.qcby.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;Target(ElementType.TYPE)// 表示该注解只能用于类上 Retention(Retentio…

Android平台下openssl动态库编译

1. 下载Linux平台下的NDK软件包 NDK 下载 | Android NDK | Android Developers 下载完成后执行解压命令 # unzip android-ndk-r27d-linux.zip 2. 下载openssl-1.1.1w源码包&#xff0c;并解压 # tar -xzvf openssl-1.1.1w.tar.gz 3. 进入解压后的openssl-1.1.1w目录 …

【C++基础】面试高频考点解析:extern “C“ 的链接陷阱与真题实战

名称修饰&#xff08;Name Mangling&#xff09;是C为支持重载付出的代价&#xff0c;而extern "C"则是跨越语言边界的桥梁——但桥上的陷阱比桥本身更值得警惕 一、extern "C" 的核心概念与高频考点1.1 链接规范与名字改编机制C 为支持函数重载&#xff0…

OpenCV 官翻 4 - 相机标定与三维重建

文章目录相机标定目标基础原理代码配置校准去畸变1、使用 cv.undistort()2、使用**重映射**方法重投影误差练习姿态估计目标基础渲染立方体极线几何目标基础概念代码练习从立体图像生成深度图目标基础概念代码附加资源练习相机标定 https://docs.opencv.org/4.x/dc/dbb/tutori…