【linux学习】linux系统调用编程

news2025/5/11 7:12:55

目录

一、任务、进程和线程

1.1任务

1.2进程

1.3线程

1.4线程和进程的关系

1.5 在linux系统下进程操作

二、Linux虚拟内存管理与stm32的真实物理内存区别

2.1 Linux虚拟内存管理

2.2 STM32的真实物理内存映射

2.3区别

三、 Linux系统调用函数 fork()、wait()、exec()

3.1 fork

3.2 wait

3.3 exec

四、在树莓派中,创建组员账号,完成练习

4.1 用户创建和配置:

4.2登录自己的树莓派账号练习

五、总结

一、任务、进程和线程

1.1任务

多任务系统指可以同一时间内运行多个应用程序的系统,每个应用程序被称作一个任务。

任务是一个逻辑概念,指由一个软件完成的任务,或者是一系列共同达到某一目的的操作。

任务的特点:

  • 在实时操作系统(RTOS)中,任务通常是独立的、无法返回的函数。

  • 任务的调度和管理依赖于任务控制块(TCB),它记录任务的状态、优先级等信息

1.2进程

进程是指一个具有独立功能的程序在某个数据集上的一次动态执行过程,它是系统进行资源分配和调度的最小单元。

通俗来说,进程就是程序的一次执行过程,程序是静态的,它作为系统中的一种资源是永远存在的。而进程是动态的,它是动态的产生,变化和消亡的,拥有其自己的生命周期。

举个例子:同时挂三个 QQ 号,它们就对应三个 QQ 进程,退出一个就会杀死一个对应的进程。但是,就算你把这三个 QQ 全都退出了,QQ 这个程序死亡了吗?显然没有。

进程不仅包含正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说 CPU、内存、网络资源等。很多小伙伴在回答进程的概念的时候,往往只会说它是一个运行的实体,而会忽略掉进程所占据的资源。比如说,同样一个程序,同一时刻被两次运行了,那么他们就是两个独立的进程。

  • 特点

    • 每个进程拥有独立的内存空间,包括代码段、数据段、堆和栈。

    • 进程之间相互隔离,一个进程的崩溃通常不会影响其他进程。

    • 进程是资源分配的最小单位,但不是CPU调度的最小单位。

1.3线程

线程是进程内独立的一条运行路线,是处理器调度的最小单元,也可以称为轻量级进程。线程——程序执行的最小单位。

  • 特点

    • 一个进程可以包含多个线程,线程共享所属进程的内存空间和资源。

    • 线程的切换开销较小,因为它只需要切换寄存器状态和栈信息。

    • 线程是程序执行的最小单位,多个线程可以并发执行。

1.4线程和进程的关系

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程;

(2)资源分配给进程,同一进程内的所有线程共享该进程的所有资源;

(3)线程在执行过程中需要协作同步。不同进程中的线程之间要利用消息通信的方法实现同步;

(4)处理机分配给线程,即真正在处理机上运行的是线程;

(5)线程是进程的一个执行单元,也是进程内的可调用实体。

1.5 在linux系统下进程操作

操作:1) 用 ps -a 命令查看系统中各进程的编号pid ; 2) 用kill 命令终止一个进程pid。

ps -a
  • ps 是“process status”的缩写,用于显示当前系统中运行的进程信息。

  • 选项-a:表示显示当前终端(TTY)中所有用户启动的进程。

我可以通过用一个sleep也来弄一个进程方便我们将他kill,如下操作:

sleep 50&
  • sleep命令用于让当前进程暂停指定的时间(单位为秒)。这里让进程暂停50秒。

  • &符号:将命令放到后台执行。这样,用户可以在命令执行的同时继续在终端中输入其他命令。

kill 1317303
  • 向PID为1317303sleep进程发送终止信号,使其停止运行。

  • 再次用ps -a查看是否终止进程。

二、Linux虚拟内存管理与stm32的真实物理内存区别

2.1 Linux虚拟内存管理

Linux操作系统采用虚拟内存管理技术,使得每个进程都有各自互不干涉的进程地址空间。

在Linux中,虚拟内存管理的基本理念是“每个程序认为它拥有独立的内存”。虚拟内存通过以下方式实现:

  • 虚拟地址与物理地址:Linux使用虚拟地址来访问内存,这些虚拟地址通过内存管理单元(MMU)映射到物理地址。虚拟地址空间被分为用户空间和内核空间,每个进程都有自己的虚拟地址空间。

  • 分页机制:Linux将内存划分为固定大小的页面(通常是4KB),并根据需要将页面从磁盘交换到物理内存中。这种机制允许系统运行比物理内存更大的程序。

  • 内存保护与隔离:虚拟内存机制提供了内存保护,确保一个进程无法访问另一个进程的内存。内核空间的内存对用户空间进程不可见。

  • 动态内存分配:Linux内核使用懒惰分配(Lazy Allocation)技术,只有当进程实际访问分配的内存时,才会分配物理内存。

  • 交换空间(Swap):当物理内存不足时,Linux会将不常用的页面交换到磁盘上的交换空间。

用户感知:程序操作的是虚拟地址,物理地址对用户透明;通过malloc()分配内存时,实际可能仅在虚拟地址空间预留范围(brkmmap),直到访问时才触发缺页异常分配物理页。

2.2 STM32的真实物理内存映射

STM32是一种嵌入式微控制器,其内存管理相对简单,主要基于物理内存的直接访问。

  • 物理内存映射:STM32使用物理内存映射,将内存和外设分配到不同的地址范围。这种映射是固定的,没有虚拟地址的概念。

  • 内存保护缺失:STM32通常没有内存保护机制,用户空间代码可以直接访问内核空间的内存。这可能导致一个程序的错误操作影响整个系统。

  • 简单的内存管理:STM32的内存管理主要依赖于静态分配,程序在启动时分配所需的内存,并在运行时直接访问这些内存。

  • 无交换空间:STM32没有交换空间的概念,所有内存操作都直接在物理内存上进行。

开发模式:程序员需手动管理内存,避免溢出。外设操作通过指针直接访问寄存器,比如常见的:

// 直接操作STM32的GPIO寄存器
#define GPIOA_ODR (*(volatile uint32_t*)0x40020014)
GPIOA_ODR |= 0x00000001; // 设置PA0引脚为高电平

2.3区别

特性Linux虚拟内存STM32物理内存映射
地址空间虚拟地址(通过MMU转换)物理地址(直接访问)
硬件依赖必须支持MMU(如ARM Cortex-A系列)无MMU(如ARM Cortex-M系列)
内存隔离进程间隔离,防止非法访问无隔离,程序可直接修改任意内存/外设
动态分配支持按需分配和交换(malloc/mmap静态分配(链接脚本定义堆栈/全局变量)
访问权限控制通过页表实现读/写/执行权限无权限控制,依赖程序员自律
典型应用场景通用计算(多任务/复杂应用)实时嵌入式系统(确定性/低延迟)

三、 Linux系统调用函数 fork()、wait()、exec()

3.1 fork

在Linux 中创建一个新进程的唯一方法是使用fork()函数。fork()函数用于从已存在的一个进程中创建一个新的进程,新进程称为子进程,而原进程称为父进程。

  • 子进程特性

    • 子进程是父进程的复制品,继承父进程的地址空间,包括代码段、数据段、堆、栈等。

    • 子进程继承父进程的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录等。

    • 子进程拥有独立的进程号(PID)和资源使用信息。

  • 返回值

    • 在父进程中,fork()返回子进程的PID。

    • 在子进程中,fork()返回0。

 1.在练习文件夹下面利用nano创建函数fork_example.c文件(建议也可以参考下文中树莓派部分的fork函数,那个比较简洁)

#include <stdio.h>      // 标准输入输出库,用于printf等函数
#include <sys/types.h>  // 包含数据类型定义,如pid_t
#include <unistd.h>     // 包含fork、getpid、getppid等函数
#include <stdlib.h>     // 包含exit函数
#include <errno.h>      // 包含错误号定义
#include <sys/wait.h>   // 包含waitpid函数及相关宏

int main() {
    pid_t pid;          // 定义一个pid_t类型的变量,用于存储fork返回的进程ID
    int ret = 1;        // 定义一个返回值变量,未在代码中使用
    int status;         // 定义一个变量,用于存储子进程退出状态

    pid = fork();       // 调用fork函数创建一个子进程

    if (pid == -1) {    // 如果fork返回-1,表示创建子进程失败
        printf("can't fork, error occured\n");  // 输出错误信息
        exit(EXIT_FAILURE);  // 退出程序,返回值为EXIT_FAILURE
    } else if (pid == 0) {  // 如果fork返回0,表示当前是子进程
        printf("child process, pid = %u\n", getpid());  // 输出子进程的PID
        printf("parent of child process, pid = %u\n", getppid());  // 输出子进程的父进程PID

        char *argv_list[] = {"ls", "-lart", "/home", NULL};  // 定义一个字符串数组,作为execv的参数
        // 调用execv替换当前进程映像为"ls"程序,并传递参数"-lart"和"/home"
        execv("ls", argv_list);  
        // 如果execv成功,控制权将转移到"ls"程序,不会返回到这里
        // 如果execv失败,返回-1,并继续执行下面的代码
        exit(0);  // 子进程退出
    } else {  // 如果fork返回一个正数,表示当前是父进程,返回值是子进程的PID
        printf("Parent of parent process, pid = %u\n", getppid());  // 输出父进程的父进程PID
        printf("parent process, pid = %u\n", getpid());  // 输出父进程的PID

        // 父进程调用waitpid等待子进程结束
        if (waitpid(pid, &status, 0) > 0) {  // 如果waitpid成功,返回子进程的PID
            // 检查子进程是否正常退出
            if (WIFEXITED(status) && !WEXITSTATUS(status))  // 如果子进程正常退出且返回值为0
                printf("program execution successful\n");
            else if (WIFEXITED(status) && WEXITSTATUS(status)) {  // 如果子进程正常退出但返回值非0
                if (WEXITSTATUS(status) == 127) {  // 如果返回值为127,表示execv失败
                    printf("execv failed\n");
                } else  // 如果返回值非127,表示程序执行完成但返回了非零状态
                    printf("program terminated normally, but returned a non-zero status\n");
            } else  // 如果子进程没有正常退出
                printf("program didn't terminate normally\n");
        } else {  // 如果waitpid失败
            printf("waitpid() failed\n");
        }
        exit(0);  // 父进程退出
    }
    return 0;  // 程序正常结束返回0
}

2.使用cmake编译fork_example.c在根目录下创建(想着用不同的方法来编译,掌握多种编译办法。也可以直接采用下文的gcc方式来编译)

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)  # 最低 CMake 版本要求
project(Fork_demo)                     # 项目名称

# 添加可执行文件
add_executable(fork_demo fork_example.c)

# 设置 C 标准(可选)
set(CMAKE_C_STANDARD 11)

3.构建目录生成文件

mkdir build && cd build

创建构建目录并生成 Makefile

cmake --build build
./build/fork_demo

运行即可,结果如图:

3.2 wait

功能:wait()函数用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()函数就会立即返回。

  • 作用

    • 确保父进程在子进程结束后再继续执行。

    • 防止子进程变成僵尸进程(zombie process)。

  • 返回值

    • 如果父进程没有子进程或者子进程已经结束,wait()会立即返回。

    • 返回值是子进程的PID。

 wait调用:

1.创建一个 fork_wait.c 文件,内容如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>  // 必须包含此头文件以使用 wait()

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork 失败");
        return 1;
    } else if (pid == 0) {
        // 子进程执行任务
        printf("子进程 PID = %d\n", getpid());
        sleep(2);  // 模拟耗时操作
        printf("子进程结束\n");
    } else {
        // 父进程等待子进程结束
        printf("父进程 PID = %d,等待子进程 %d...\n", getpid(), pid);
        int status;
        wait(&status);  // 阻塞等待子进程结束
        printf("子进程退出状态: %d\n", WEXITSTATUS(status));
    }
    return 0;
}

同样的创建Makefile,

# 定义编译器和编译选项
CC = gcc
CFLAGS = -Wall -Wextra -std=c11

# 定义目标可执行文件名和源文件
TARGET = fork_wait_demo
SRC = fork_wait.c

# 默认目标
all: $(TARGET)

# 编译规则
$(TARGET): $(SRC)
	$(CC) $(CFLAGS) -o $@ $^

# 清理生成的文件
clean:
	rm -f $(TARGET)

# 伪目标声明(避免与同名文件冲突)
.PHONY: all clean

编译运行效果:

make
./fork_wait_demo

结果演示:

3.3 exec

在Linux 中使用exec函数族主要有两种情况:
1.当进程认为自己不能再为系统和用户做出任何贡献时,他就可以发挥最后一点余热,调用任何一个exec,让自己以新的面貌重生;
2.如果一个进程想执行另一个程序,那么它就可以调用fork() 函数新建一个进程,然后调用exec 函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。

exec调用:

可以先建一个文件夹哈(这样方便看到保存每个函数的那个记录,我上面两个函数忘记创建了,之后做实验最好一个实验一个文件夹,这样清爽一些)

mkdir exec && cd exec

1.创建 fork_exec.c 文件,参考代码:

#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程执行 ls -l
        execl("/bin/ls", "ls", "-l", NULL);
        perror("exec failed"); // 若 exec 失败才会执行
        return 1;
    }
    return 0;
}

2.可以用gcc或者make或者cmake等方式来进行编译,我们这里就用常规简单一点的gcc(cmake和make的方式上面两个函数都有代码,修改一下名称就可以用啦)

gcc fork_exec.c -o fork_demo
./fork_demo

结果演示:

四、在树莓派中,创建组员账号,完成练习

4.1 用户创建和配置:

提前进入到主要的账号里边给各个用户加上相关的权限,操作如下(putty和Xterminal都可以)

1.使用adduser命令创建用户

sudo adduser zsc
  • 执行后会提示设置密码及用户信息(非必填项可直接回车跳过)

  • 默认自动生成同名主目录 /home/username

2.配置用户权限

1.将用户加入sudo组

sudo usermod -aG sudo zsc

2.加入常用硬件访问组

sudo usermod -aG adm,dialout,plugdev zsc

3. 验证用户权限

id zsc  # 查看用户所属组
groups zsc  # 列出用户所有附加组

4.2登录自己的树莓派账号练习

在Xterminal中利用ssh连接登陆上自己的树莓派账号。(连接过程和之前的博客步骤一样的,通过电脑移动热点查询物理地址,账号密码确认后即可登录)

我们还可以查看树莓派下面的其他用户

compgen -u

进入到自己的树莓派环境中

配置一下安装一下环境:

在树莓派Ubuntu系统中,默认可能未安装GCC,安装GCC及编译所需的工具链(如makeg++等)

sudo apt update
sudo apt install build-essential

1.创建并打开目录

mkdir test0404 && cd test0404

2.编写fork.c程序(选用gcc的方式来编译啦,这样快捷一些)

nano fork_gcc.c

简单的编写一个代码:

#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork失败\n");
        return 1;
    } else if (pid == 0) {
        printf("子进程ID: %d\n", getpid());
    } else {
        printf("父进程ID: %d,子进程ID: %d\n", getpid(), pid);
    }
    return 0;
}

3.编译并运行:

gcc fork_gcc.c -o fork_gcc

//编译需要卡一会

./fork_gcc

五、总结

通过本次让我收获很大很大,本文主要阐述了任务、进程、线程的定义,区别和联系,参考文献1中有更加直白易懂的说法(感兴趣的可以去看看),同时通过查阅资料阐述了虚拟机内存管理和STM32的物理内存中的一些差别,进一步了解虚拟机和存储的方式;最后也是本次最重要的实践环节,学习调用了fork、wait、exec函数,深入理解了每个函数在树莓派的中是如何使用的,同时每个函数的调用用了不同的编译方法(cmake、make、gcc)(个人建议设计内容少的函数可以直接用gcc是最方便的),加深了对Ubuntu的运用和理解,同时通过反反复复的敲代码和命令,对整体的编程水平还是上升了不少,感兴趣的朋友也可以自己试试手敲,收获会很大的。

树莓派的操作也越来越熟悉了,在XTerminal很好用,建议用这个,很不错。

本文中原理部分有些图片来源于网络,如有侵权请及时与我联系删除,本人才疏学浅,如有描述不准确或出错的地方还请海涵,感谢您的阅读!

参考文献:

https://zhuanlan.zhihu.com/p/391496775

https://zhuanlan.zhihu.com/p/403313422

Linux系统调用编程-CSDN博客

Linux Ubuntu 入门基本命令整理_linux ubuntu入门基本命令整理-CSDN博客

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

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

相关文章

Azure Speech 赋能,为智能硬件注入 AI 语音 “新灵魂”

在人工智能技术飞速发展的今天&#xff0c;智能硬件正逐步渗透到人们生活的方方面面。AI玩具、AI眼镜、AI鼠标等创新产品不仅提升了用户体验&#xff0c;更带来了前所未有的交互方式。领驭科技凭借微软Azure Speech的强大技术能力&#xff0c;为硬件厂商提供一站式AI语音解决方…

SignalR给特定User发送消息

1、背景 官网上SignalR的demo很详细&#xff0c;但是有个特别的问题&#xff0c;就是没有详细阐述如何给指定的用户发送消息。 2、解决思路 网上整体解决思路有三个&#xff1a; 1、最简单的方案&#xff0c;客户端连接SignalR的Hub时&#xff0c;只是简单的连接&#xff0c…

React: hook相当于函数吗?

一、Hook 是一个函数&#xff0c;但不仅仅是函数 函数的本质 Hook 确实是一个 JavaScript 函数&#xff0c;例如 useState、useEffect 或自定义 Hook 都是函数。它们可以接受参数&#xff08;如初始状态值或依赖项数组&#xff09;&#xff0c;并返回结果&#xff08;如状态值和…

【数据分享】2002-2023中国湖泊水位变化数据集(免费获取)

湖泊水位变化是研究水资源动态、生态系统演变和气候变化影响的重要指标。湖泊水位的升降不仅反映了降水、蒸发和入流水量的变化&#xff0c;还与人类活动、气候波动及地质过程密切相关。因此&#xff0c;高精度、长时间序列的湖泊水位数据对于水资源管理、洪水预测以及生态环境…

免费送源码:Java+SSM+Android Studio 基于Android Studio游戏搜索app的设计与实现 计算机毕业设计原创定制

摘要 本文旨在探讨基于SSM框架和Android Studio的游戏搜索App的设计与实现。首先&#xff0c;我们详细介绍了SSM框架&#xff0c;这是一种经典的Java Web开发框架&#xff0c;由Spring、SpringMVC和MyBatis三个开源项目整合而成&#xff0c;为开发企业级应用提供了高效、灵活、…

STM32单片机入门学习——第14节: [6-2] 定时器定时中断定时器外部时钟

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.04 STM32开发板学习——第14节: [6-2] 定时器定时中断&定时器外部时钟 前言开发…

2025-04-03 Latex学习1——本地配置Latex + VScode环境

文章目录 1 安装 Latex2 安装 VScode3 配置环境3.1 汉化 VScode3.2 安装 latex 插件3.3 配置解释 4 编译示例5 加快你的编译5.1 取消压缩5.2 使用 PDF 代替图片 6 参考文章 1 安装 Latex 本文配置环境&#xff1a; Windows11 打开清华大学开源软件镜像站&#xff1a;https://mi…

【CF】Day24——Codeforces Round 994 (Div. 2) D

D. Shift Esc 题目&#xff1a; 思路&#xff1a; 典DP的变种 如果这一题没有这个变换操作&#xff0c;那么是一个很典型的二维dp&#xff0c;每一个格子我们都选择上面和左边中的最小值即可 而这题由于可以变换&#xff0c;那我们就要考虑变换操作&#xff0c;首先一个显然…

【Java集合】LinkedList源码深度分析

参考笔记&#xff1a;java LinkedList 源码分析&#xff08;通俗易懂)_linkedlist源码分析-CSDN博客 目录 1.前言 2.LinkedList简介 3.LinkedList的底层实现 4.LinkedList 与 ArrayList 的对比 4.1 如何选择 4.2 对比图 5.LinkedList 源码Debug 5.1 add(E e) &#xff…

Python办公自动化(2)对wordpdf的操作

一、操作word文档 终端下载操作word文件的工具库&#xff1a; pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx 1.遍历文档中内容 paragraphs&#xff1a;段落属性&#xff0c;返回列表类型的段落地址&#xff0c;遍历每一个段落地址&#xff0c;通过…

pip安装第三方库,但PyCharm中却无法识别

点击菜单栏File&#xff0c;选择Settings 系统默认的是PyCharm安装目录下的python.exe 解释器&#xff0c;不要用。 选择你的PYTHON的安装目录下的python.exe 解释器。如果不存在的话&#xff0c;增加进去 如果文件》设置打不开&#xff0c;需移除法化包。 打开 pycharm 安装目…

Linux C++编译及g++使用操作

编译的步骤 编译选项参数 编译生成库文件 静态库 动态库 运行可执行文件 静态库由于已经包含了链接的文件所以可以直接执行&#xff1b;动态库方式由于是运行时链接&#xff0c;所以需要指定链接的路径&#xff1b;

【Android】界面布局-线性布局LinearLayout-例子

线性布局&#xff08;LinearLayout&#xff09;是一种重要的界面布局中&#xff0c;也是经常使用到的一种界面布局 • 在线性布局中&#xff0c;所有的子元素都按照垂直或水平的顺序在界面上排列 ➢如果垂直排列&#xff0c;则每行仅包含一个界面元素 ➢如果水平排列&…

windows技术基础知识

NT架构 NT 就是new techonology 的英文单词缩写&#xff0c;是微软1993年推出操作系统的重大升级&#xff0c;如内存管理&#xff0c;安全机制&#xff0c;多任务&#xff0c;多线程支持。在此之前操作系统都是基于MS-DOS上面的图形化界面&#xff0c;只有有限的内存管理和多任…

在 Windows 环境下使用 VSCode 和 TinyGo 开发 ESP8266(NodeMcu) or STM32

支持的型号 https://tinygo.org/docs/reference/microcontrollers/ 1. 安装Go 2. 安装TinyGo&#xff0c;并添加环境变量 https://github.com/tinygo-org/tinygo/releases 3. VSCode配置&#xff0c;安装插件&#xff0c;选择设备 package mainimport ("machine"&q…

计算机视觉算法实战——基于YOLOv8的汽车试验场积水路段识别系统

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 引言&#xff1a;汽车试验场智能化管理的迫切需求 在现代汽车研发流程中&#xff0c;试验场作为验证车辆性…

One API:LLM API 管理 分发系统,github 24.2K Star!

随着人工智能领域的不断发展&#xff0c;国内外各大厂商纷纷推出了自己的 AI 大模型。面对 DeepSeek、OpenAI、Claude、腾讯元宝等众多平台的 API 接口差异&#xff0c;开发者常常需要花费大量时间调整代码、处理密钥管理与流量调控。One API 正是在这种背景下诞生&#xff0c;…

Android Settings 有线网设置界面优化

Android Settings 有线网设置界面优化 文章目录 Android Settings 有线网设置界面优化一、前言二、简单修改1、修改的EthernetSettings代码&#xff1a;2、有线网ip获取代码&#xff1a;3、AndroidManifest.xml定义有线网的Activity4、修改后界面&#xff1a; 三、其他1、有线网…

正则入门到精通

​ 一、正则表达式入门​ 正则表达式本质上是一串字符序列&#xff0c;用于定义一个文本模式。通过这个模式&#xff0c;我们可以指定要匹配的文本特征。例如&#xff0c;如果你想匹配一个以 “abc” 开头的字符串&#xff0c;正则表达式可以写作 “^abc”&#xff0c;其中 …

微信小程序基于Canvas实现头像图片裁剪(上)

序言 嘿&#xff0c;打工人混迹职场这么久&#xff0c;图片处理肯定都没少碰。不过咱说实话&#xff0c;大部分时候都是直接 “抄近道”&#xff0c;用现成的三方组件&#x1f60f;。就像我&#xff0c;主打一个会用工具&#xff0c;毕竟善用工具可是咱人类的 “超能力”&…