【读书笔记-《30天自制操作系统》-22】Day23

本篇内容比较简单,集中于显示问题。首先编写了应用程序使用的api_malloc,然后实现了在窗口中画点与画线的API与应用程序。有了窗口显示,还要实现关闭窗口的功能,于是在键盘输入API的基础上实现了按下按键关闭窗口。最后发现用上文的强制结束按键结束应用程序,程序的窗口还没有关闭,又增加了强制结束程序时关闭窗口的功能。
在这里插入图片描述

1. 实现api_malloc

在上一篇中,显示窗口定义了char buf[150 * 50]。编译之后,相当于增加了150*50个字节的0x00,导致编译后的应用程序大了很多。为了精简应用程序的大小,这里改为使用分配的内存空间。

为应用程序分配内存空间,不能直接使用操作系统管理内存的memman_alloc函数。因为应用程序不能直接读写操作系统管理的内存,这样会产生异常并强制结束应用程序。应用程序可以读写的仅仅是操作系统为其分配好的内存空间,位于数据段中。

这里我们在应用程序中写好需要使用的内存大小。指定内存大小的数值后,会和栈等的大小相累加,写入到.hrb文件最开头的4个字节中。这个内存空间在数据段中的开始位置,被保存在.hrb文件的0x0020处。
设计API如下:

menman初始化:

  • EDX = 8
  • EBX = memman的地址
  • EAX = memman所管理内存空间的起始地址
  • ECX = memman所管理的内存空间的字节数

malloc:

  • EDX = 9
  • EBX = memman的地址
  • ECX = 需要请求的字节数
  • EAX = 分配到的内存空间地址

free:

  • EDX = 10
  • EBX = memman的地址
  • EAX = 需要释放的内存空间地址
  • ECX = 需要释放的字节数

根据以上设计,在hrb_api中增加以下处理:

int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{int ds_base = *((int *) 0xfe8);struct TASK *task = task_now();struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);struct SHEET *sht;int *reg = &eax + 1;	/* reg[0] : EDI,   reg[1] : ESI,   reg[2] : EBP,   reg[3] : ESP *//* reg[4] : EBX,   reg[5] : EDX,   reg[6] : ECX,   reg[7] : EAX */if (edx == 1) {cons_putchar(cons, eax & 0xff, 1);} else if (edx == 2) {cons_putstr0(cons, (char *) ebx + ds_base);} else if (edx == 3) {cons_putstr1(cons, (char *) ebx + ds_base, ecx);} else if (edx == 4) {return &(task->tss.esp0);} else if (edx == 5) {sht = sheet_alloc(shtctl);sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);sheet_slide(sht, 100, 50);sheet_updown(sht, 3);	reg[7] = (int) sht;} else if (edx == 6) {sht = (struct SHEET *) ebx;putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base);sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16);} else if (edx == 7) {sht = (struct SHEET *) ebx;boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi);sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);} else if (edx == 8) {memman_init((struct MEMMAN *) (ebx + ds_base));ecx &= 0xfffffff0;	/* 以16字节为单位 */memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);} else if (edx == 9) {ecx = (ecx + 0x0f) & 0xfffffff0; /* 以16字节为单位进位取整 */reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx);} else if (edx == 10) {ecx = (ecx + 0x0f) & 0xfffffff0; /* 以16字节为单位进位取整 */memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);}return 0;
}

应用程序调用的api:

_api_initmalloc:	; void api_initmalloc(void);PUSH	EBXMOV		EDX,8MOV		EBX,[CS:0x0020]		; malloc内存空间的地址MOV		EAX,EBXADD		EAX,32*1024			; 加上32KBMOV		ECX,[CS:0x0000]		; 数据段的大小SUB		ECX,EAXINT		0x40POP		EBXRET_api_malloc:		; char *api_malloc(int size);PUSH	EBXMOV		EDX,9MOV		EBX,[CS:0x0020]MOV		ECX,[ESP+8]			; sizeINT		0x40POP		EBXRET_api_free:			; void api_free(char *addr, int size);PUSH	EBXMOV		EDX,10MOV		EBX,[CS:0x0020]MOV		EAX,[ESP+ 8]		; addrMOV		ECX,[ESP+12]		; sizeINT		0x40POP		EBXRET

应用程序:

int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_end(void);void HariMain(void)
{char *buf;int win;api_initmalloc();buf = api_malloc(150 * 50);win = api_openwin(buf, 150, 50, -1, "hello");api_boxfilwin(win,  8, 36, 141, 43, 6 /* 浅蓝色 */);api_putstrwin(win, 28, 28, 0 /* 黑色 */, 12, "hello, world");api_end();
}

运行程序之后可以实现同样的功能,但是应用程序文件大大减小了。
在这里插入图片描述

2. 画点、线与刷新窗口

接下来就进入图形处理,分别来描绘点和线。

1.1 描绘点

在窗口中画点的设计很简单:

  • EDX = 11
  • EBX = 窗口句柄
  • ESI = 显示位置的x坐标
  • EDI = 显示位置的y坐标
  • EAX = 色号

应用程序调用的api和应用程序的代码也比较简单。

应用程序调用API:

_api_point:		; void api_point(int win, int x, int y, int col);PUSH	EDIPUSH	ESIPUSH	EBXMOV		EDX,11MOV		EBX,[ESP+16]	; winMOV		ESI,[ESP+20]	; xMOV		EDI,[ESP+24]	; yMOV		EAX,[ESP+28]	; colINT		0x40POP		EBXPOP		ESIPOP		EDIRET

操作系统API:

……
else if (edx == 11) 
{sht = (struct SHEET *) ebx;sht->buf[sht->bxsize * edi + esi] = eax;sheet_refresh(sht, esi, edi, esi + 1, edi + 1);
}
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_point(int win, int x, int y, int col);
void api_end(void);void HariMain(void)
{char *buf;int win;api_initmalloc();buf = api_malloc(150 * 100);win = api_openwin(buf, 150, 100, -1, "star1");api_boxfilwin(win,  6, 26, 143, 93, 0 /* 黑色*/);api_point(win, 75, 59, 3 /* 黄色 */);api_end();
}

实现的功能也比较简单,只是在窗口中显示一个点:

在这里插入图片描述
还可以用随机数的方式在窗口中显示多个点:

int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_point(int win, int x, int y, int col);
void api_end(void);int rand(void);		/* 0-32767之间的随机数 */void HariMain(void)
{char *buf;int win, i, x, y;api_initmalloc();buf = api_malloc(150 * 100);win = api_openwin(buf, 150, 100, -1, "stars");api_boxfilwin(win,  6, 26, 143, 93, 0 /* 黑色 */);for (i = 0; i < 50; i++) {x = (rand() % 137) +  6;y = (rand() %  67) + 26;api_point(win, x, y, 3 /* 黄色*/);}api_end();
}

在这里插入图片描述

在上面生成多个点的程序中,每生成一个点都会执行一次刷新窗口的操作。其实可以在描绘完所有点之后统一进行一次刷新。刷新窗口的句柄是struct SHEET的地址,是一个偶数。这样可以在所有窗口绘图命令中设置一个选项和一个仅用于刷新的API:

……
else if (edx == 11) 
{sht = (struct SHEET *) (ebx & 0xfffffffe);sht->buf[sht->bxsize * edi + esi] = eax;if ((ebx & 1) == 0) {sheet_refresh(sht, esi, edi, esi + 1, edi + 1);}
}
else if (edx == 12) 
{sht = (struct SHEET *) ebx;sheet_refresh(sht, eax, ecx, esi, edi);
}
……

以上的处理,当ebx结尾为0,即偶数时,执行刷新窗口的操作。应用程序调用的执行刷新的API:

_api_refreshwin:	; void api_refreshwin(int win, int x0, int y0, int x1, int y1);PUSH	EDIPUSH	ESIPUSH	EBXMOV		EDX,12MOV		EBX,[ESP+16]	; winMOV		EAX,[ESP+20]	; x0MOV		ECX,[ESP+24]	; y0MOV		ESI,[ESP+28]	; x1MOV		EDI,[ESP+32]	; y1INT		0x40POP		EBXPOP		ESIPOP		EDIRET

修改后的应用程序:

int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_point(int win, int x, int y, int col);
void api_end(void);int rand(void);		/* 0-32767的随机数 */void HariMain(void)
{char *buf;int win, i, x, y;api_initmalloc();buf = api_malloc(150 * 100);win = api_openwin(buf, 150, 100, -1, "stars");api_boxfilwin(win,  6, 26, 143, 93, 0 /* 黑色 */);for (i = 0; i < 50; i++) {x = (rand() % 137) +  6;y = (rand() %  67) + 26;api_point(win, x, y, 3 /* 黄色 */);}api_end();
}

1.2 描绘直线

描绘直线的基本方法:

for(i = 0; i < len; i++)
{
api_point(win, x, y, col);
x += dx;
y += dy;
}

len为线的长度,x,y为线的起始坐标,dx和dy表示线延伸的方向。
dx和dy既不能太大,导致线看起来像虚线,又不能太小,导致CPU多次在同一个坐标画点。
程序如下:

……
else if (edx == 13) 
{sht = (struct SHEET *) (ebx & 0xfffffffe);hrb_api_linewin(sht, eax, ecx, esi, edi, ebp);if ((ebx & 1) == 0) {sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);}
}
……
void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col)
{int i, x, y, len, dx, dy;dx = x1 - x0;dy = y1 - y0;x = x0 << 10;y = y0 << 10;if (dx < 0) {dx = - dx;}if (dy < 0) {dy = - dy;}if (dx >= dy) {len = dx + 1;if (x0 > x1) {dx = -1024;} else {dx =  1024;}if (y0 <= y1) {dy = ((y1 - y0 + 1) << 10) / len;} else {dy = ((y1 - y0 - 1) << 10) / len;}} else {len = dy + 1;if (y0 > y1) {dy = -1024;} else {dy =  1024;}if (x0 <= x1) {dx = ((x1 - x0 + 1) << 10) / len;} else {dx = ((x1 - x0 - 1) << 10) / len;}}for (i = 0; i < len; i++) {sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col;x += dx;y += dy;}return;
}

当前还不能处理小数。为了处理dx,dy更加精确,采用了将x和y预先扩大1024倍的方法,这样增加1024实际上就是增加1。
可以看出计算长度的方法比较粗糙,通过比较起点和终点的x,y坐标,将变化比较大的一方加上1作为长度len。这是因为当起点与终点相同时,需要在画面上显示一个点。而计算dx和dy时应用了一个小技巧:根据直线延伸的方向,将变化较大的一方设为1024或-1024,而将变化较小的一方的变化量除以len。这样的计算方式能够使描绘出的直线更平滑一些。
应用程序代码:

_api_linewin:		; void api_linewin(int win, int x0, int y0, int x1, int y1, int col);PUSH	EDIPUSH	ESIPUSH	EBPPUSH	EBXMOV		EDX,13MOV		EBX,[ESP+20]	; winMOV		EAX,[ESP+24]	; x0MOV		ECX,[ESP+28]	; y0MOV		ESI,[ESP+32]	; x1MOV		EDI,[ESP+36]	; y1MOV		EBP,[ESP+40]	; colINT		0x40POP		EBXPOP		EBPPOP		ESIPOP		EDIRET
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_initmalloc(void);
char *api_malloc(int size);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_end(void);void HariMain(void)
{char *buf;int win, i;api_initmalloc();buf = api_malloc(160 * 100);win = api_openwin(buf, 160, 100, -1, "lines");for (i = 0; i < 8; i++) {api_linewin(win + 1,  8, 26, 77, i * 9 + 26, i);api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i);}api_refreshwin(win,  6, 26, 154, 90);api_end();
}

运行程序,绘制出了几条直线:
在这里插入图片描述

3. 键盘输入API

接下来我们来做通过键盘按键结束API的功能。

键盘输入

  • EDX = 15
  • EAX = 0——没有键盘输入时返回-1,不休眠
  • EAX = 1——休眠直到发生键盘输入
  • EAX = 输入的字符编码
else if (edx == 15) {for (;;) {io_cli();if (fifo32_status(&task->fifo) == 0) {if (eax != 0) {task_sleep(task);	/* FIFO为空,休眠并等待 */} else {io_sti();reg[7] = -1;return 0;}}i = fifo32_get(&task->fifo);io_sti();if (i <= 1) { /* 光标用定时器 *//*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1 */timer_init(cons->timer, &task->fifo, 1); /* 下次置为1 */timer_settime(cons->timer, 50);}if (i == 2) {	/* 光标ON */cons->cur_c = COL8_FFFFFF;}if (i == 3) {	/* 光标OFF */cons->cur_c = -1;}if (256 <= i && i <= 511) { /* 键盘数据(通过任务A) */reg[7] = i - 256;return 0;}}}

由于应用程序窗口的光标显示需要用到定时器,于是也将其包含到struct CONSOLE之中了。

struct CONSOLE {struct SHEET *sht;int cur_x, cur_y, cur_c;struct TIMER *timer;
};

键盘输入的API如下:

_api_getkey:		; int api_getkey(int mode);MOV		EDX,15MOV		EAX,[ESP+4]	; modeINT		0x40RET
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_initmalloc(void);
char *api_malloc(int size);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_closewin(int win);
int api_getkey(int mode);
void api_end(void);void HariMain(void)
{char *buf;int win, i;api_initmalloc();buf = api_malloc(160 * 100);win = api_openwin(buf, 160, 100, -1, "lines");for (i = 0; i < 8; i++) {api_linewin(win + 1,  8, 26, 77, i * 9 + 26, i);api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i);}api_refreshwin(win,  6, 26, 154, 90);for (;;) {if (api_getkey(1) == 0x0a) {break; /* 按下回车键则break; */}}api_closewin(win);api_end();
}

运行程序,显示出直线;按下回车键,窗口消失。
在这里插入图片描述

接下来用键盘实现一个小程序:

int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_closewin(int win);
int api_getkey(int mode);
void api_end(void);void HariMain(void)
{char *buf;int win, i, x, y;api_initmalloc();buf = api_malloc(160 * 100);win = api_openwin(buf, 160, 100, -1, "walk");api_boxfilwin(win, 4, 24, 155, 95, 0 /* 黑色 */);x = 76;y = 56;api_putstrwin(win, x, y, 3 /* 黄色 */, 1, "*");for (;;) {i = api_getkey(1);api_putstrwin(win, x, y, 0 /* 黑色 */, 1, "*"); /* 用黑色擦除 */if (i == '4' && x >   4) { x -= 8; }if (i == '6' && x < 148) { x += 8; }if (i == '8' && y >  24) { y -= 8; }if (i == '2' && y <  80) { y += 8; }if (i == 0x0a) { break; } /* 按回车结束 */api_putstrwin(win, x, y, 3 /* 黄色 */, 1, "*");}	api_closewin(win);api_end();
}

运行程序,窗口中的’*'在按下2,4,6,8键时可以上下左右地移动。
在这里插入图片描述

4. 关闭窗口

最后还有一个问题,使用上一篇完成的Shift+F1按键结束程序时,程序结束后窗口仍然保留在屏幕上。因为上一篇的强制结束按键在结束程序后没有消除窗口,因此这一结果也在预料之中。

解决这个问题也很简单。在struct SHEET中添加一个用来存放task的成员,当应用程序结束时,查询所有的图层,找到图层中与结束的程序一样的task,将该图层关闭就可以了。

修改struct SHEET:

struct SHEET {unsigned char *buf;int bxsize, bysize, vx0, vy0, col_inv, height, flags;struct SHTCTL *ctl;struct TASK *task;
};

需要修改的程序代码:

struct SHEET *sheet_alloc(struct SHTCTL *ctl)
{struct SHEET *sht;int i;for (i = 0; i < MAX_SHEETS; i++) {if (ctl->sheets0[i].flags == 0) {sht = &ctl->sheets0[i];sht->flags = SHEET_USE; /* 正在使用 */sht->height = -1; /* 不显示 */sht->task = 0;	/* 不使用自动关闭功能 */return sht;}}return 0;	
}
……} else if (edx == 5) {sht = sheet_alloc(shtctl);sht->task = task; //给sht->task赋值sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);sheet_slide(sht, 100, 50);sheet_updown(sht, 3);	reg[7] = (int) sht;}
……
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{
……struct SHTCTL *shtctl;struct SHEET *sht;
……if (finfo != 0) {/* 找到文件的情况 */p = (char *) memman_alloc_4k(memman, finfo->size);file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {……start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0));shtctl = (struct SHTCTL *) *((int *) 0x0fe4);for (i = 0; i < MAX_SHEETS; i++) {sht = &(shtctl->sheets0[i]);if (sht->flags != 0 && sht->task == task) {/* 找到应用程序遗留的窗口 */sheet_free(sht);	/* 关闭该窗口*/}}memman_free_4k(memman, (int) q, segsiz);} else {cons_putstr0(cons, ".hrb file format error.\n");}memman_free_4k(memman, (int) p, finfo->size);cons_newline(cons);return 1;}return 0;
}

这样在运行程序时,按下Shift+F1,结束程序的同时也可以关闭窗口了。
在这里插入图片描述

本篇内容比较简单,思路清晰,程序代码也不需要多作解释,大多还是利用前面完成的内容。下一篇中将继续开发窗口的功能,敬请期待。

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

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

相关文章

诗文发布模板(python代码打造键盘录入诗文自动排版,MarkDown源码文本)

python最好用的f-string&#xff0c;少量代码打造键盘录入诗文自动排版。 (笔记模板由python脚本于2024年09月19日 19:11:50创建&#xff0c;本篇笔记适合喜欢写诗的pythoner的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&am…

Apache subversion 编译流程

目录 1. 概述2. 依赖库简介2.1 Expat2.2 Apache apr2.3 Apache apr-iconv2.4 Apache apr-util2.5 Zlib2.6 OpenSSL2.7 Sqlite2.8 Apache Serf2.9 Apache subversion3. 编译3.1 Expat编译3.1.1 源码信息3.1.2 CMake-GUI3.1.3 编译步骤3.2 APR编译3.2.1 源码信息3.2.2 编译步骤3.…

【笔记】2.1 半导体三极管(BJT,Bipolar Junction Transistor)

一、结构和符号 1. 三极管结构 常用的三极管的结构有硅平面管和锗合金管两种类型。各有PNP型和NPN型两种结构。 左图是NPN型硅平面三极管,右图是PNP型锗合金三极管。 从图中可见平面型三极管是先在一块大的金属板上注入杂质使之变成N型,然后再在中间注入杂质使之变成P型,…

倒序循环(一)

题目描述 输入一个正整数n&#xff0c;输出从 n~ 1 递减的序列。 输入格式 一行一个整数 n 输出格式 n 行&#xff0c;每行一个符合题目要求的整数 样例数据 样例输入#1 5样例输出#1 5 4 3 2 1样例输入#2 6样例输出#2 6 5 4 3 2 1数据范围 对于100%的数据&#xff…

Java企业面试题2

1.语言的分代&#xff1a; 第1代&#xff1a;机器语言 机器语言是最底层的计算机编程语言&#xff0c;它是由二进制数构成的一系列指令&#xff0c;直接与计算机硬件交互。每个二进制位模式代表一条特定的指令或数据地址。因为它是直接在硬件上执行的&#xff0c;所以运行效率…

Java 23 的12 个新特性!!

Java 23 来啦&#xff01;和 Java 22 一样&#xff0c;这也是一个非 LTS&#xff08;长期支持&#xff09;版本&#xff0c;Oracle 仅提供六个月的支持。下一个长期支持版是 Java 25&#xff0c;预计明年 9 月份发布。 Java 23 一共有 12 个新特性&#xff01; 有同学表示&…

xmake与包管理:又一个现代c++构建工具?

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 主要起因是我在逛Reddit帖子时,看到关于一些c构建系统的评价. cmake似乎有些过于复杂,它与vcpkg,conan的包管理之间的"融合"可能在有些时候也显得麻烦. 一些人尝试了我没见过的选项, 所以这里主要试试除了…

Java重修笔记 第五十七天 坦克大战(七)多线程基础 - 编程练习

1. 线程之间的协调控制&#xff08;通知方式&#xff09; public class Homework04 {public static void main(String[] args) {// 在 main 方法中启动两个线程// 第一个线程内循环打印 1 到 100 以内的整数// 直到第二个线程从键盘读取到 "Q" 指令后结束第一个线程…

深入剖析大模型原理——Qwen Blog

1. 输入部分 Text&#xff1a;原始输入文本&#xff0c;模型需要处理的自然语言数据。Tokenizer&#xff1a;分词器&#xff0c;将输入文本转换为词汇表中的索引&#xff08;ID&#xff09;&#xff0c;便于后续处理。Input_ids&#xff1a;经过分词处理后的ID序列&#xff0c…

交流回馈老化测试负载的智能升级

在电子设备的生产过程中&#xff0c;老化测试是不可或缺的环节。老化测试主要是通过模拟设备长时间工作的情况&#xff0c;检测设备在经过一定时间的使用后&#xff0c;其性能是否会发生降低&#xff0c;是否存在安全隐患等。老化测试负载是老化测试中的重要组成部分&#xff0…

今日所学啊

ArcGIS打不开焦点统计如何解决_arcgis焦点统计打不开-CSDN博客 好吧其实最后焦点统计还是不行&#xff0c;我就去ArcGIS Pro里做焦点统计了哈哈哈哈哈哈哈 visual studio多工程项目管理_visual studio 的模块管理-CSDN博客 1.今天成功#include <QNetworkReply>不画红线…

【MYSQL表的增删改查(基础)】

MYSQL表的增删改查&#xff08;基础&#xff09; 一、CRUD二、新增&#xff08;Create&#xff09;2.1 单行数据全列插入2.2 多行数据指定列插入 三、查询&#xff08;Retrieve&#xff09;3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.3.1 表达式不包含字段3.3.2 表达式包…

react是什么?

文章目录 核心特点1. **组件化**2. **虚拟 DOM** 3. **声明式编程**4. **单向数据流**5. **JSX 语法**6. **Hooks** react的优势劣势 React 是一个由 Facebook 开发和维护的开源 JavaScript 库&#xff0c;用于构建用户界面&#xff0c;特别是单页应用程序&#xff08;SPA&…

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能&#xff0c;但是遇到了如下问题&#xff1a; 在Unity里面没法串流调试眼动追踪功能&#xff0c;根本获取不到Device&#xff0c;只能将整个场景build成APK&#xff0c;安装到头盔里&#xff0c;才能在…

枚举(not二分)

前言&#xff1a;这一题似乎用不了二分以及三分&#xff0c;害我写这么久&#xff0c;但是查找下一个元素的时候要用到二分查找 题目地址 #include<bits/stdc.h> using namespace std; #define endl "\n"int n; const int N (int)2e510; vector<int> a;…

OceanBase 中 schema 的定义与应用

背景 经常在OceanBase 的问答社区 里看到一些关于 “schema 是什么” 的提问。 先纠正一些同学的误解&#xff0c; OceanBase 中的 Schema 并不简单的等同于 Database&#xff0c;本次分享将探讨 OceanBase 中的Schema是什么&#xff0c;及一些大家经常遇到的问题。 具体而…

JavaDS —— 图

图的概念 图是由顶点集合以及顶点之间的关系组成的一种数据结构&#xff1a;G &#xff08;V&#xff0c;E&#xff09; 其中 V 表示的是顶点集合 &#xff1a; V { x | x 属于某个数据对象集} 是有穷非空集合 E 叫做边的集合 &#xff1a; E {(x, y) | x, y 属于 V} 或者 …

UE5源码Windows编译、运行

官方文档 Welcome To Unreal Engine 5 Early Access Learn what to expect from the UE5 Early Access program. 链接如下&#xff1a;https://docs.unrealengine.com/5.0/en-US/Welcome/#gettingue5earlyaccessfromgithub Step 0&#xff1a;找到UE5源码 直接先上链接 https…

MySQL原理之UUID主键分析,插入或更新语法分析

文章目录 1 MySQL不能用UUID做主键1.1 前言1.2 mysql和程序实例1.2.1 准备工作1.2.2 开始测试1.2.3 程序写入结果1.2.4 效率测试结果 1.3 使用uuid和自增id的索引结构对比1.3.1 自增id1.3.2 uuid 1.4 自增id缺点1.5 雪花算法 2 插入或更新2.1 on duplicate key2.1.1 定义2.1.2 …

24年蓝桥杯及攻防世界赛题-MISC-3

21 reverseMe 复制图片&#xff0c;在线ocr识别&#xff0c;https://ocr.wdku.net/&#xff0c;都不费眼睛。 22 misc_pic_again ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc/zsteg] └─$ zsteg misc_pic_again.png imagedata … text: “$$KaTeX parse error: Undefined…