我的OS | 为切换到C语言做准备

分享如何快速定位代码在哪里崩掉了(bochs+NASM汇编) 调试汇编代码是一场艰辛晦涩的旅程,幸好有bochs,幸好有各种提示信息,为这场旅行带来了一丝的光明:今天分分享如何快速定位代码在哪里崩掉了: u /10 00007cb3: ( ): mov ebx, 0x00040000 ; bb00000400 00007cb8: ( ): mov di, 0x 阅读详情

注意啊,没看下面的文章的要先看看下面的,再看这一篇啊。

我们刚才成功从启动层跳转到了内核程序,现在就应该从内核程序执行C语言了。但是,由于现在的CPU处于实模式中,而我们计划使用保护模式,所以要先切换过来。

在实模式中,我们只可以使用1MB以下的内存,所以我们需要先打开这个。

具体讲解如下。

首先我们要屏蔽所有的中断。万一哪个用户在切换CPU模式的时候碰了一下鼠标,就不好办了。所以,我们需要禁用所有中断。

完成以上命令只需要几行程序。

; 禁用所有PIC中断
; 由于OUT指令的第二个操作数(数据)必须是寄存器
mov al, 0xff
; 将0xff发送给PIC(0xff代表全部的一,禁用所有中断)
; 0x21是主PIC的端口
out 0x21, al
; 如果连续执行out指令,有的CPU无法执行
nop
; 然后禁用来自从PIC的中断
out 0xa1, al
; 禁止CPU级别的中断
cli

哎,大家可能只有在看笔者的程序时才会看到注释比程序还要多的情况呢。

接下来,我们要让CPU可以使用1MB以上的内存。这是因为CPU为了兼容以前的操作系统,在激活之前只可以使用1MB的内存。

; 下面的内容是函数,应确保CPU不会擅自执行
wait_KBD_out:
  ; 读取PIC中积攒的数据
  in al, 0x64
  and al, 0x02
  ; 清空垃圾数据
  in al, 0x60
  ; 如果AND指令的结果不是0就重新跳转到wait_KBD_out
  ; Jump if not zero(不是零则跳转)
  jnz wait_KBD_out
  ; 返回
  ret
; 让CPU能访问1MB以上的内存
; 读取
call wait_KBD_out
; 数据
mov al, 0xd1
; 发送信号
out 0x64, al
; 读取
call wait_KBD_out
; 启用的信号
mov al, 0xdf
; 发送信号
out 0x60, al
; 继续读取
call wait_KBD_out

然后,CPU就可以访问1MB以上的内存了。

接下来,我们要让CPU切换到保护模式。

切换到保护模式只需要让CPU中CR0寄存器的bit0为1就可以了。当然,在此之前,我们要先设定临时的GDT。

; 以下是数据段,也要确保CPU不会擅自执行
; 判断地址是否可以被16整除
alignb 16
tmp_gdt:
  ; 空
  resb 8
  ; 可读写的段,32bits
  dw 0xffff, 0x0000, 0x9200, 0x00cf
  ; 可执行的段,32bits(C程序用)
  dw 0xffff, 0x0000, 0x9a28, 0x0047
gdtr0:
  ; 很简单的程序,看不懂就不要看了
  dw 8 * 3 - 1
  ; tmp_gdt的内容
  dd tmp_gdt
  ; 判断地址是否可以被十六整除
  alignb 16
; 设置临时的GDT
lgdt [gdtr0]
; 读取Control Register 0的内容到EAX寄存器中
mov eax, cr0
; 设置EAX寄存器的值
; 设置bits31为0(为了禁止分页,我们想要使用分段)
and eax, 0x7fffffff
; 设置bit0为1(切换到保护模式)
or eax, 0x00000001
; 将EAX寄存器中的值重新写入到CR0中
mov cr0, eax
; 切换CPU模式后需要执行跳转指令才能启用
jmp init_protect_mode
init_protect_mode:
  ; 在GDT中设定的可读写的段
  mov ax, 1 * 8
  ; 初始化所有的段寄存器(在启用保护模式后都会改变)
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  mov ss, ax

到这里,CPU应该就已经是保护模式的状态了。接下来,我们要执行C语言程序。

C语言的程序其实最终是和kernel.asm连为一体的(生成的机器语言会结合为一体),所以,只需要在kernel.asm的最后留下一个标号C_kernel然后跳转到该标号就可以了。

; 必须由汇编处理的到此为止,接下来加载C语言的程序
; C语言程序最终会被加载到后面的标号C_kernel中
jmp C_kernel
C_kernel:

好的,kernel.asm的源代码就是这样的

org 0x7e00
; 初始化寄存器
; mov指令将右边的寄存器或数的值复制到右边的寄存器中
; 将CS(Code Segment)的值赋给AX寄存器
mov ax, cs
; 将AX寄存器(从CS寄存器取来)的值赋给DS(Data Segment)寄存器
mov ds, ax
; 将AX寄存器的值赋给ES(Extra Segment)寄存器
mov es, ax
; 将AX寄存器的值赋给SS(Stack Segment)寄存器
mov ss, ax
; 将这段代码的起始位置赋值给SP寄存器(Stack Point)
mov sp, 0x7e00
; 调整画面模式
; int 0x10 AH寄存器 = 0x00 切换显卡的模式
  ; AL = 显卡的模式
    ; 0x03 16色的字符模式,80 x 25
    ; 0x12 VGA图形模式,640 x 480 x 4位彩色模式,独特的4面存储模式
    ; 0x13 VGA图形模式,320 x 200 x 8位彩色模式,调色板模式
    ; 0x6a 扩展VGA图形模式,800 x 600 x 4位彩色模式,独特的4面存储模式(有的显卡不支持这个模式)
mov ax, 0x0013
int 0x10
; 禁用所有PIC中断
; 由于OUT指令的第二个操作数(数据)必须是寄存器
mov al, 0xff
; 将0xff发送给PIC(0xff代表全部的一,禁用所有中断)
; 0x21是主PIC的端口
out 0x21, al
; 如果连续执行out指令,有的CPU无法执行
nop
; 然后禁用来自从PIC的中断
out 0xa1, al
; 禁止CPU级别的中断
cli
; 让CPU能访问1MB以上的内存
; 读取
call wait_KBD_out
; 数据
mov al, 0xd1
; 发送信号
out 0x64, al
; 读取
call wait_KBD_out
; 启用的信号
mov al, 0xdf
; 发送信号
out 0x60, al
; 继续读取
call wait_KBD_out
; 设置临时的GDT
lgdt [gdtr0]
; 读取Control Register 0的内容到EAX寄存器中
mov eax, cr0
; 设置EAX寄存器的值
; 设置bits31为0(为了禁止分页,我们想要使用分段)
and eax, 0x7fffffff
; 设置bit0为1(切换到保护模式)
or eax, 0x00000001
; 将EAX寄存器中的值重新写入到CR0中
mov cr0, eax
; 切换CPU模式后需要执行跳转指令才能启用
jmp init_protect_mode
init_protect_mode:
  ; 在GDT中设定的可读写的段
  mov ax, 1 * 8
  ; 初始化所有的段寄存器(在启用保护模式后都会改变)
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  mov ss, ax
; 必须由汇编处理的到此为止,接下来加载C语言的程序
; C语言程序最终会被加载到后面的标号C_kernel中
jmp C_kernel
; 下面的内容是函数,应确保CPU不会擅自执行
wait_KBD_out:
  ; 读取PIC中积攒的数据
  in al, 0x64
  and al, 0x02
  ; 清空垃圾数据
  in al, 0x60
  ; 如果AND指令的结果不是0就重新跳转到wait_KBD_out
  ; Jump if not zero(不是零则跳转)
  jnz wait_KBD_out
  ; 返回
  ret
; 以下是数据段,也要确保CPU不会擅自执行
; 判断地址是否可以被16整除
alignb 16
tmp_gdt:
  ; 空
  resb 8
  ; 可读写的段,32bits
  dw 0xffff, 0x0000, 0x9200, 0x00cf
  ; 可执行的段,32bits(C程序用)
  dw 0xffff, 0x0000, 0x9a28, 0x0047
gdtr0:
  ; 很简单的程序,看不懂就不要看了
  dw 8 * 3 - 1
  ; tmp_gdt的内容
  dd tmp_gdt
  ; 判断地址是否可以被十六整除
  alignb 16
C_kernel:


我们执行一下试试:

虚拟机看起来在不断重启,开始还以为是bug,后来一想,本来C_kernel就是一个空的标号,而且,翻一翻日志信息还可以看到类似于以下的内容:

这行信息说明了CPU正在保护模式中,所以kernel.asm运行的很正常!

我们修改一下源代码,让C_kernel不是一个空的标号。

org 0x7e00
; 初始化寄存器
; mov指令将右边的寄存器或数的值复制到右边的寄存器中
; 将CS(Code Segment)的值赋给AX寄存器
mov ax, cs
; 将AX寄存器(从CS寄存器取来)的值赋给DS(Data Segment)寄存器
mov ds, ax
; 将AX寄存器的值赋给ES(Extra Segment)寄存器
mov es, ax
; 将AX寄存器的值赋给SS(Stack Segment)寄存器
mov ss, ax
; 将这段代码的起始位置赋值给SP寄存器(Stack Point)
mov sp, 0x7e00
; 调整画面模式
; int 0x10 AH寄存器 = 0x00 切换显卡的模式
  ; AL = 显卡的模式
    ; 0x03 16色的字符模式,80 x 25
    ; 0x12 VGA图形模式,640 x 480 x 4位彩色模式,独特的4面存储模式
    ; 0x13 VGA图形模式,320 x 200 x 8位彩色模式,调色板模式
    ; 0x6a 扩展VGA图形模式,800 x 600 x 4位彩色模式,独特的4面存储模式(有的显卡不支持这个模式)
mov ax, 0x0013
int 0x10
; 禁用所有PIC中断
; 由于OUT指令的第二个操作数(数据)必须是寄存器
mov al, 0xff
; 将0xff发送给PIC(0xff代表全部的一,禁用所有中断)
; 0x21是主PIC的端口
out 0x21, al
; 如果连续执行out指令,有的CPU无法执行
nop
; 然后禁用来自从PIC的中断
out 0xa1, al
; 禁止CPU级别的中断
cli
; 让CPU能访问1MB以上的内存
; 读取
call wait_KBD_out
; 数据
mov al, 0xd1
; 发送信号
out 0x64, al
; 读取
call wait_KBD_out
; 启用的信号
mov al, 0xdf
; 发送信号
out 0x60, al
; 继续读取
call wait_KBD_out
; 设置临时的GDT
lgdt [gdtr0]
; 读取Control Register 0的内容到EAX寄存器中
mov eax, cr0
; 设置EAX寄存器的值
; 设置bits31为0(为了禁止分页,我们想要使用分段)
and eax, 0x7fffffff
; 设置bit0为1(切换到保护模式)
or eax, 0x00000001
; 将EAX寄存器中的值重新写入到CR0中
mov cr0, eax
; 切换CPU模式后需要执行跳转指令才能启用
jmp init_protect_mode
init_protect_mode:
  ; 在GDT中设定的可读写的段
  mov ax, 1 * 8
  ; 初始化所有的段寄存器(在启用保护模式后都会改变)
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax
  mov ss, ax
; 必须由汇编处理的到此为止,接下来加载C语言的程序
; C语言程序最终会被加载到后面的标号C_kernel中
jmp C_kernel
; 下面的内容是函数,应确保CPU不会擅自执行
wait_KBD_out:
  ; 读取PIC中积攒的数据
  in al, 0x64
  and al, 0x02
  ; 清空垃圾数据
  in al, 0x60
  ; 如果AND指令的结果不是0就重新跳转到wait_KBD_out
  ; Jump if not zero(不是零则跳转)
  jnz wait_KBD_out
  ; 返回
  ret
; 以下是数据段,也要确保CPU不会擅自执行
; 判断地址是否可以被16整除
alignb 16
tmp_gdt:
  ; 空
  resb 8
  ; 可读写的段,32bits
  dw 0xffff, 0x0000, 0x9200, 0x00cf
  ; 可执行的段,32bits(C程序用)
  dw 0xffff, 0x0000, 0x9a28, 0x0047
gdtr0:
  ; 很简单的程序,看不懂就不要看了
  dw 8 * 3 - 1
  ; tmp_gdt的内容
  dd tmp_gdt
  ; 判断地址是否可以被十六整除
  alignb 16
C_kernel:
  jmp $

然后执行一下。

欸,为什么还是在重启呢?

笔者看了看日志信息,发现有这样一句话:

00014146775e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00014146775e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)

意思就是说,这个段是一个无效的,所以CPU在重启。他还说了

EIP=0000004c (0000004c)

就是说,CPU将要执行0x7e00:0x004c处的指令。我们翻一翻lst文件就可以了。

就是说CPU正在执行mov ss, ax这条指令,然后还有一句

00014146775e[CPU0  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting

CPU是听了shutdown status这个东西,然后就重启了。

根据CPU说的东西,我们能知道,是我们的GDT有问题。

笔者还是想要跳过这个bug,于是将这段初始化寄存器的代码注释掉了。没想到,注释掉后能够正常运行?笔者打开debug模式,获取了段寄存器的值。

???这个bochs不会是太先进了吧?

于是笔者在VMWare上实验了一下。

果然,将这段代码注释掉就可以正常运行,不注释掉就会报一般保护性异常。。。

好吧,虽然今天成功切换到了保护模式,但是还有很多需要问BIOS的东西没有问,我们现在来问一问。

首先是画面的模式。这个我们可以在C语言中定义为一个常量,但是笔者还是想要在汇编中获取然后保存到0x0ff0处。

其次,是键盘上所有灯的状态。Capslock与Numlock都要从这里获取。

最后就是内存的大小了。这个不用我说了吧。

; 键盘上的LED灯
LEDS equ 0x0ff0
; 画面模式
VMODE equ 0x0ff1
; 分辨率X
SCRNX equ 0x0ff3
; 分辨率Y
SCRNY equ 0x0ff5
; VRAM的起始位置
VRAM equ 0x0ff7
; 调整画面模式
; int 0x10 AH寄存器 = 0x00 切换显卡的模式
  ; AL = 显卡的模式
    ; 0x03 16色的字符模式,80 x 25
    ; 0x12 VGA图形模式,640 x 480 x 4位彩色模式,独特的4面存储模式
    ; 0x13 VGA图形模式,320 x 200 x 8位彩色模式,调色板模式
    ; 0x6a 扩展VGA图形模式,800 x 600 x 4位彩色模式,独特的4面存储模式(有的显卡不支持这个模式)
mov ax, 0x0013
int 0x10
; int 0x16 AH = 0x02 获取键盘指示灯状态
; 中断号码
mov ah, 0x02
; 调用中断
int 0x16
; 将AL寄存器中获取的值存放到内存地址LEDS中
mov [LEDS], al
; 画面模式
mov byte [VMODE], 8
; 分辨率X
mov word [SCRNX], 320
; 分辨率Y
mov word [SCRNY], 200
; VRAM的起始位置
mov dword [VRAM], 0x000a0000

运行。

啊,果然还是不行啊。具体为什么,我们明天再研究。肯定是段寄存器的问题,不过也挺好,一步一个脚印的走着才会有进步嘛。加油!我的Cunix!

你学会了吧?

µC/OS-II 在 STM32F103 上的移植核心要点解析 实时操作系统(RTOS)是嵌入式系统实现多任务并发与确定性响应的关键技术。其核心原理在于基于硬件异常(如 PendSV、SysTick)的任务上下文切换、临界区保护机制与可重入代码设计。技术价值体现在资源可控、响应及时、模块隔离强,广泛应用于工业控制、智能传感与边缘设备等对可靠性与实时性要求严苛的场景。理解 Cortex-M3 双堆栈模型、中断向量表对齐、os_cpu.h 架构适配及 OSTaskStkInit 栈初始化逻辑,是成功移植 µC/OS-II 的基础前提。 阅读详情

相关推荐

操作系统核心概念与任务切换器C语言实战

在操作系统中,进程(Process)是程序的一次执行实例,是资源分配和调度的基本单位。进程不仅仅是代码的执行,还包括程序运行时所依赖的数据、堆栈、寄存器状态、文件句柄等资源。操作系统通过进程来隔离程序之间的执行环境,确保它们不会互相干扰。进程具有多种状态,常见的状态包括:状态说明就绪态(Ready)进程已准备好运行,等待CPU分配运行态(Running)正在被CPU执行的进程阻塞态(Blocked)等待某些事件(如I/O完成)发生后才能继续执行。

weixin_42573757的博客 319

实模式跳转到保护模式,在保护模式打印一个字符串。

<br />调试结果是:<br />单步执行到保护模式下的打印字符串,当执行完lodsb后一句时,出现出错提示。<br /> <br />请看错误提示:<br /><bochs:17> <br /> Next at t=106268085<br /> (0) [0x00032484] 0018:0000001c (unk. ctxt): cld                       ; fc<br /> <bochs:18> <br /> Next at t=106268086<br />

Just do IT 4414

GD32F303C移植μC/OS-III实战:从工程结构到任务切换的完整指南

嵌入式实时操作系统(RTOS)通过任务调度与中断管理机制,为多任务并发提供确定性响应,是提升系统实时性和可维护性的关键。在国产化替代趋势下,Cortex-M4内核的GD32F303C凭借与STM32的引脚兼容性,成为许多产品从裸机向RTOS升级的热门选择。然而,GD32与ST的外设库、时钟树及中断细节存在差异,直接将STM32的UCOSIII工程“魔改”往往导致HardFault。本文基于实际工程,系统拆解μC/OS-III在GD32F303C上的移植全过程:从源码目录结构、启动文件与SysTick/Pen

weixin_34130389的博客 423

ExpOS:一个从0开始的中文OS

Windows下编译、运行演示: 1.到sf.linuxfourm.net下载编译工具包, ExpOS编译工具包 2.解压缩到c:根目录, 改名为djgpp. 3.下载一个0.0.7.2, 双击build目录的osgo.bat. 4.在控制台下输入make就可以编译. 5.编译完成后build目录生成一个 flp文件, 把vmware的a驱设置为这个文件, 就可以使用vmware...

weixin_33825683的博客 283

立创开源便携式多生理参数监护仪:基于STM32H743与ADS1292R的心电血氧体温监测系统设计

本文详细解析了基于STM32H743与ADS1292R的便携式多生理参数监护仪开源设计。项目集成了心电、血氧和体温监测功能,采用模块化硬件架构,并重点介绍了利用FIR滤波和Pan-Tompkins算法进行心电信号处理的核心技术。文章提供了完整的复刻指南与避坑要点,是学习医疗电子设备设计的优秀实践案例。

weixin_30600615的博客 327

从零到一:移远EC200UCN_LA OpenCPU开发中的‘避坑’实战指南

本文详细介绍了移远EC200UCN_LA 4G通信模块的OpenCPU开发实战指南,涵盖开发环境搭建、项目构建、通信接口开发、调试技巧及固件升级等关键环节。通过避坑经验和实用技巧,帮助开发者高效完成二次开发,提升4G通信模块的应用开发效率。

weixin_29159711的博客 504

[书]x86汇编语言:从实模式到保护模式 -- 第14章 任务和特权级保护,调用门、LDT、TSS、TCB

#加载用户程序 Part 1、TCB, Task Control Block, 任务控制块 分配内存作为该任务的TCB,并插入至TCB链表。 Part 2、LDT, Locak Descriptor, 局部描述符表 分配内存作为该任务的LDT。 为用户程序的各个段构建段描述符,并写入LDT。 将LDT写入GDT,得到对应的选择子。 将LD...

trb331617的博客 1237

Seafile搭建以及onlyoffice在线办公

部署seafile docker-compose.yml 如下: 参考此篇文章 version: '2.0' services: db: image: mariadb:10.1 container_name: seafile-mysql environment: - MYSQL_ROOT_PASSWORD=db_dev # mysql root的密码,同时修改 seafile的DB_ROOT_PASSWD与这个一致 - MYSQL_LOG_CONSOLE

dwdcth的专栏 4656

C语言笔试准备

经常要操作的内存分为哪几个类别?线程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。线程间可以直接读写进程数据段(如全局变量)来通信。线程上下文切换要比进程快。使用哈夫曼算法编码后,用编码值来存储这段文本将花费最少的存储空间。使用哈夫曼算法进行编码,编码值可以有多套,但每个字符编码的位是确定的。哈夫曼树带权路径长度最短的树,路径上全值较大的节点离根较近。当从一个最小堆删除一个元素时,需要把堆尾元素填补到堆顶位置,然后再按条件把它逐层向下调整到合适位置。

Caramel_biscuit的博客 991

单片机控制双向可控硅的5种实用触发电路设计(附完整电路图)

本文深入解析了单片机控制双向可控硅的5种实用触发电路设计,涵盖从基础隔离到复杂负载驱动的实战方案。重点探讨了光电耦合器选型、过零检测同步、RC吸收电路精密计算以及应对感性负载和高噪声环境的加固策略,并提供了完整的电路图与调试避坑指南,旨在帮助开发者实现安全可靠的交流负载控制。

joy55的博客 2204

SAP LTMC实战指南:物料主数据高效导入全解析

本文详细解析了SAP LTMC工具在物料主数据高效导入中的实战应用,包括工具选择、项目搭建、模板定制、数据导入全流程及常见问题解决方案。重点介绍了LTMC的预置模板、LTMOM灵活配置、数据校验机制等核心功能,帮助用户快速掌握SAP数据迁移技巧,提升工作效率。

weixin_33738555的博客 434

【一】笨方法学c语言-learn c the hard way

笨方法学C语言译文

qq_50789384的博客 616

3、灵巧手的设计与构造

本文详细探讨了灵巧手的设计与构造,包括多指结构、关节和连杆设计、传感器集成以及分层控制架构等内容。同时,通过工业装配、医疗手术辅助和日常生活辅助等实际应用案例,展示了灵巧手的灵活性和适应性,并分析了当前设计面临的挑战及未来发展方向。

brandy的博客 488

任务是如何调度(切换)的?

<br />学习任务的切换有助于自己理解操作系统的运行过程。并且任务的调度(切换)也是操作系统中的重要的部分。任务的切换中关键是任务控制块的控制,将现在以及将来要运行的任务向堆栈中的存储与恢复。<br />       因为μC/OS-II总是运行进入就绪状态的最高优先级的任务。所以,确定哪个任务优先级最高,下面该哪个任务运行,这个工作就是由调度器(scheduler)来完成的。<br />       任务级的调度是由函数OSSched()完成的,而中断级的调度是由函数OSIntExt()完成。对于OSS

zhw888888的专栏 3485

【ComfyUI】Z-Image 基础文生图 + 单LoRA

本文介绍了一个基于ComfyUI的Z-Image Turbo基础文生图工作流,采用轻量化UNet模型配合Qwen Image文本理解模型与LoRA风格注入,实现从文本到图像的快速生成。工作流结构清晰,包含模型加载、文本编码、采样解码等标准节点,在人物生成、构图稳定性和出图速度方面表现均衡。通过调整Prompt可控制生成内容,适合日常创作、教学演示及扩展进阶应用。

Mr数据杨 922

A100 NVLink集群极致优化指南

《A100 NVLink集群通信优化指南》摘要:针对A100 80G SXM机型NVLink 3.0集群,提供硬件配置检查方法(nvidia-smi topo -m)和强制启用指令。重点介绍NCCL参数调优(算法选择、低延迟协议配置)、GPUDirect RDMA启用步骤,以及单机/多机场景下的通信模式选择。包含PyTorch all_reduce基准测试方法,并给出带宽异常排查方案(dmesg检查、NCCL缓存重置)。通过CUDA Graph通信重叠和混合精度优化,可实现90%+带宽利用率。附猿界算力监控

2401_89353317的博客 583

1个系统节拍 c语言_μC/OS-II操作系统详解(1)

µC/OS-II的特点 UC/OS是一个非常小巧的实时操作系统;整个代码分为内核层以及移植层,这样使得它的植 性很方便。 采用抢占式调度策略,保证任务的实时性。  能够管理多达64个任务。  提供了邮箱、消息队列、信号量、内存管理、 时间管理等系统服务。µC/OS-II的各种商业应用  全世界有数百种产品在应用:  医疗器械 移动电话  路由器  工业控制  GPS 导航系统 ...

weixin_42717586的博客 1304

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C语言游戏 双缓存解决闪屏问题 详细总结

最近,应学校课程要求,要完成一个C语言课程设计。可以是写一个小游戏,或是写管理系统等。 所以,准备做一个改版贪吃蛇:消灭小虫虫(瞎起的名字 :D)。 之前学过Java,所以学C语言也就比较顺利。而在刚学完C语言刚着手准备做C语言的小游戏时,却发现了一个问题——闪屏。 (我在网上查找了很多关于双缓存,有关的解答很少,更少能够让一个完全不了解的小白一个明白的解释。下面我想和大家分享我使用...

YoungITの博客 15万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

AIGlasses OS Pro入门:C语言基础开发环境搭建

本文介绍了如何在星图GPU平台上一键自动化部署👓 AIGlasses OS Pro智能视觉系统镜像,快速搭建C语言开发环境。通过一个简单的LED闪烁程序示例,展示了该镜像在智能眼镜视觉应用开发中的基础应用,帮助开发者快速入门嵌入式视觉编程。

weixin_36064575的博客 252

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

μC/OS-II

准备在51单片机上移植这个操作系统。要求:内存尽量小,只要能满足当前的功能,预留一写扩展。稳定,满足实时性要求。 μC/OS-II 是一种基于优先级的抢占式多任务实时操作系统,包含了实时内核、任务管理、时间管理、任务间通信同步(信号量,邮箱,消息 队列)和内存管理等功能。它可以使各个任务独立工作,互不干涉,很容易实现准时而且无误执行,使实时应用程序的设计和扩展变得容易,使应用程序的设计过

icodec的专栏 785

零基础集成AIGlasses OS Pro:C语言API快速上手,嵌入式视觉开发入门

本文介绍了如何在星图GPU平台上自动化部署👓 AIGlasses OS Pro智能视觉系统镜像,快速构建嵌入式AI视觉开发环境。该平台简化了部署流程,使开发者能便捷地利用该镜像提供的C语言API,为智能眼镜等设备集成轻量级目标检测与手势识别功能,实现高效的嵌入式视觉应用开发。

weixin_42577735的博客 73

QML程序实现动态切换多语言

QML程序实现动态切换多语言 Qt程序中实现多语言有Qt自己的一套机制,然而目前在5.9版本下该机制无法在程序运行期间动态切换语言。本文向大家介绍一种切实可行的walkaround方法,支持对普通文本以及在ListModel/ListElement中的文本的多语言处理。 回顾Qt多语言机制 Qt自身的多语言机制分下面几个步骤: 在源码中用QObject::tr()(C++)或者qsTr()(QML)将字符串包起来; 用Qt自带的lupdate生成.ts文件; 用linguist工具翻译并发布为.qm文件;

qq_45477402的博客 1501

iOS app语言切换

本文介绍了iOS应用实现多语言切换的技术方案。主要内容包括:1)在项目中添加多语言支持并创建.string文件存储翻译文本;2)实现LanguageManager类管理语言切换,提供设置语言、获取本地化字符串等功能;3)通过通知机制处理语言切换后的界面更新;4)在AppDelegate中初始化默认语言,并在界面上使用本地化字符串。该方案支持简体中文、繁体中文和英文三种语言,通过NSBundle加载对应语言资源文件实现文本替换,并提供了完整的语言切换和界面刷新机制。

qq_43441647的博客 511

别再只学应用层编程了!用C语言动手写一个能运行的OS内核(稀缺教程)

掌握底层编程核心技能,从C语言实现简易操作系统内核入门开始。本文带你用C语言动手编写可运行的OS内核,涵盖启动流程、内存管理与中断处理,适合嵌入式和系统开发学习者,原理清晰、步骤详实,值得收藏。

PixelShoal的博客 839
上一篇: 什么是栈
下一篇: 我的OS | 从启动层加载内核程序
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值