【计算机组成与体系结构Ⅱ】虚拟存储器以及虚拟变换(实验)

news2024/12/22 19:50:21

实验7:虚拟存储器以及虚拟变换

一、实验目的

1:加深对虚拟存储器基本概念、基本组织结构以及基本工作原理的理解。

2:掌握页式、段式,段页式存储的原理以及地址变换的方法。

3:理解LRU与随机替换的基本思想。

二、实验平台

    在Dev-C++软件上,运行或修改VA-Converting.cpp文件。

三、实验内容与步骤

3.1 学习虚拟地址变换的基本操作,了解基本工作原理


1:启动虚拟地址变化模拟器。


2:运行程序,设计测试地址,思考模拟器地址变化的原理。

在上图中,测试的逻辑地址是300。物理地址的计算公式为:逻辑地址的块号 * 页面大小 + 页内地址。其中,逻辑地址块号的计算公式为:逻辑地址块号 = 逻辑地址 / 页面大小。页内地址的计算公式为:页内地址 = 逻辑地址 % 页面大小。

综上所述,模拟器地址变化主要依靠逻辑地址和物理地址之间的映射。

3:思考物理地址和虚拟地址空间大小。


    由下图打印的信息可知,pa对应虚拟地址的页号,d对应虚拟地址的页内地址,n对应所映射的物理地址的页号,m对应所映射的物理地址。


物理地址的空间大小 = 物理页号最大值 * 页面大小 + 最大页面地址。其中,物理页号的最大值为25,页面大小为1KB(1024B),最大页面地址为1023B(页面大小减去1)。


虚拟地址的空间大小 = 虚拟页号最大值 * 页面大小 + 最大页面地址。其中,虚拟页号的最大值为1024(即字母l对应的大小),页面大小为1KB(1024B),最大页面地址为1023B(页面大小减去1)。

3.2 打开源代码

1:分析示例程序的源码中,页表用什么数据结构实现的?替换算法用的什么?

页面是用结构体搭建的哈希表实现的。Page中包含一个虚拟地址的页号和一个所映射的物理地
址页号,且总共设置了15个虚拟页。

替换算法采用了LRU算法,是用栈实现的。

2:分析虚拟变换过程是如何实现的,替换算法是如何实现的?


虚拟变化过程的实现:利用页表进行实现。首先对用户输入的逻辑地址进行分解和转换,分别得到虚拟页号pa、页内地址d。再利用locate函数,通过传入的虚拟页号得到物理页号。

 其中,locate函数的实现如下所示。首先遍历所有虚拟页,对比当前位置虚拟页号和函数传入的虚拟页号是否相等。如果相等,则返回结构体中所保存的物理页号,否则继续下一次遍历。如果最终没有对应的物理页号,则返回-1,表示函数传入的虚拟页号和当前系统中的物理页号没有映射关系。

替换算法的实现:利用栈进行实现。如果栈内是非满状态的话(即存在空闲的页表),首先判断该页是否在栈内,如果不在栈内则进行入栈操作,如果在栈内则调用其位置于栈顶(即最近最常访问内容的位置往前靠)。如果栈内是满状态的话(即不存在空闲的页表),首先判断该页是否在栈内,如果不在栈内则进行入栈操作,并将栈底的内容弹出(即替换掉最近最不常访问的内容),如果在栈内则调用其位置于栈顶(即最近最常访问内容的位置往前靠)。

3:分析cache的大小,cache的地址变换用什么数据结构实现?

本程序中没有设置cache。

3.3 自行设计地址变换模拟器

1:用C、C++或者熟悉任意语言编程实现虚拟地址变换过程。

2:虚拟地址32位,物理地址16位,每页大小2K、Cache大小2K、直接映像、块大小32B。

3:输入采用16进制(或10进制)的地址,通过随机方法进行替换。(可自行设计一个初始的页表数据)

4:采用一级页表方式。

5:运行需要输出虚拟地址变换后的物理地址,以及Cache块的索引和块内地址、是否命中。

【分析】

1:页式结构分析

页面大小2K = 2^11

虚拟地址32位,空间大小为2^32,页面数量为2^32 / 2^11 = 2^21个

物理地址16位,空间大小为2^16,分块数量为2^16 / 2^11 = 2^5 = 32个

2:Cache结构分析

Cache大小2K = 2^11,块大小32B = 2^5,Cache块数为2^11 / 2^5 = 2^6 = 64块

Cache是直接映像,每组对应1块,所以Cache的行数和组数都是64

3:地址映射分析

页面号 = 虚拟地址 / 页面大小

页内地址 = 虚拟地址 % 页面大小

主存块号:计算出的页面号在页表内进行一一映射

物理地址 = 主存块号 * 页面大小 + 页内地址

4:Cache命中分析

Cache索引 = 物理地址 / Cache块大小 % Cache块数

Cache块内地址 = 物理地址 % Cache块大小

其中,Cache块大小 = 32B

【测试用例】


1:执行随机页面置换算法

 使用【功能1】,输入页面总数为10,页面号从0~9随机输入(此处的序列为0、1、2、3、6、5、4、7、9、8)。当存储页面的栈处于满状态时,栈内执行随机替换算法,即新插入的页面替换掉栈中的某页面。最终的结果如上图所示。


2:地址变换


使用【功能2】,输入逻辑地址为300。程序通过计算逻辑页面和页内地址,将逻辑页面在页表中找到其对应的物理块号后,可以计算出逻辑地址所映射的物理地址为2048 * 7 + 300 = 14636。Cache再对物理地址进行检索,本测试中Cache命中,对应的Cache行是14636 / 32 % 64 = 9,块内地址是14636 % 32 = 12。最终的结果如上图所示。

当用户输入的逻辑地址过大时,程序会提示【地址越界】,结果如上图所示。


3:退出程序系统

 使用【功能3】,打印“结束使用!”字样,程序运行完毕。结果如上图所示。

【源代码】

import random

# 栈类,用于管理页面号的栈

class SqStack:

    def __init__(self):

        self.stack = []  # 栈的存储结构

        self.max_size = 5  # 栈的最大容量!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

       

    def push(self, item):

        # 将一个元素推入栈中

        if len(self.stack) < self.max_size:

            self.stack.append(item)

    def is_full(self):

        # 判断栈是否已满

        return len(self.stack) == self.max_size

    def is_empty(self):

        # 判断栈是否为空

        return len(self.stack) == 0

    def find(self, item):

        # 查找栈中是否含有某个元素

        return item in self.stack

    def print_stack(self):

        # 打印栈的内容

        print(self.stack)

# 页面类,用于管理页面和内存

class Page:

    def __init__(self):

        self.page_table = {}  # 页面表

        self.page_len = 65536  # 页面总数

        self.l = 2048  # 页面大小

        # 初始化页面表

        for i in range(self.page_len):

            j = random.randint(0, 10)

            self.page_table[i] = i + j

    def locate(self, n):

        # 根据页面号查找对应的块号

        return self.page_table.get(n, -1)

# 地址转换函数

def address_translation(page, address):

    # 计算页面号和偏移量

    page_number = address // page.l

    if not (0 <= page_number < page.page_len):

        print("地址越界")

        return -1

    offset = address % page.l

    # 获取块号并计算物理地址

    block_number = page.locate(page_number)

    if block_number != -1:

        physical_address = block_number * page.l + offset

        print(f"页号: {page_number}, 块号: {block_number}, 偏移量: {offset}")

        print(f"物理地址 = {physical_address}")

        return physical_address

    else:

        print("此地址没有对应的条目")

        return -1

# 随机页面置换函数

def random_page_replacement(stack, page_number):

    # 若栈未满且页面号不存在于栈中,则入栈

    if not stack.is_full():

        if not stack.find(page_number):

            stack.push(page_number)

            return True

    # 若栈已满且页面号不存在于栈中,则随机替换一个元素

    else:

        if not stack.find(page_number):

            replace_index = random.randint(0, stack.max_size - 1)

            stack.stack[replace_index] = page_number

            return True

    return False

def main():

    page = Page()

    stack = SqStack()

    cache = [None] * 64  # 初始化缓存

    cache_v = 32

    while True:

        print("**********菜单***********")

        print("1 - 执行随机页面置换算法")

        print("2 - 地址变换")

        print("3 - 退出")

        print("*************************")

        choice = input("请输入菜单号:")

        if choice == "1":

            while True:

                try:

                    n = int(input("请输入页面数:"))

                    if n > 100:

                        print("输入的数值太大!!")

                        continue

                    break

                except ValueError:

                    print("请输入一个有效的整数!")

            page_sequence = []

            for _ in range(n):

                while True:

                    try:

                        page_number = int(input("请输入页面号 (0~~9)"))

                        if 0 <= page_number <= 9:

                            page_sequence.append(page_number)

                            break

                        else:

                            print("请输入一个介于 0 9 之间的整数!")

                    except ValueError:

                        print("请输入一个有效的整数!")

            for page_number in page_sequence:

                random_page_replacement(stack, page_number)

                stack.print_stack()

        elif choice == "2":

            # 执行地址变换

            print("页面大小是 2kb")

            print("物理地址 = 其所对块号 * 页面大小 + 页内地址")

            adr = int(input("请输入逻辑地址:"))

            physical_address = address_translation(page, adr)

            if physical_address != -1:

                cache_index = physical_address // cache_v % len(cache)

                offset = physical_address % cache_v

                cache[cache_index] = physical_address // cache_v

                print(f"物理地址 {physical_address} 对应的 cache 索引为:{cache_index}")

                print(f"物理地址 {physical_address} 对应的 cache 块内地址为:{offset}")

        elif choice == "3":

            # 退出程序

            print("结束使用!")

            break

if __name__ == "__main__":

    main()

3.4 思考问题并简要回答

1:如果替换算法改为FIFO,需要对哪些数据结构以及算法进行改进?

  1. 数据结构:使用队列或列表,用于追踪页面的加载顺序。
  2. 算法改进:修改页面置换函数,使其按照 FIFO 的逻辑运行。即当缓存满的时候,移除最早加载的页面。

2:如果采用TLB快表,则需如何改进方案?

TLB快表用于加速虚拟地址到物理地址的转换过程。

  1. 数据结构:使用数组或列表,用于存储最近的地址转换。
  2. 算法改进:在进行地址转换之前,先在 TLB 快表中查找。如果在快表中找到该地址,则直接使用;如果在快表中没有找到该地址,进行常规地址转换,并将结果存入快表中。

3:如果虚拟地址大小、物理地址大小、虚页大小、cache大小、cache块大小、相联度等参数可以通过用户输入的情况,需要对哪些部分进行改进?

  1. 用户输入改进:设置允许用户输入各种参数的模块,并设置相应的变量进行保存,以便于函数调用时进行传参操作。
  2. 数据结构调整:
    (1)页面和页大小:根据用户输入的虚拟页大小和物理地址大小调整页面的数据结构。
    (2)Cache 结构:基于用户输入的 cache 大小和块大小调整 cache 的数据结构。如果实现了相联 cache(直接映射、全相联、组相联),则需要根据相联度来组织 cache 的存储方式。
  3. 算法调整:
    (1)地址转换:修改地址转换逻辑以适应新的虚拟地址和物理地址大小。计算页号和偏移量的方式需要根据新的页面大小进行调整。
    (2)Cache 管理:根据新的 cache 参数调整 cache 的管理策略,例如数据的存储、检索、替换等。
    (3)页面置换算法:页面置换算法需要根据新的页面大小进行调整,例如使用FIFO、LRU、随机替换算法等。
  4. 参考代码如下所示:

def get_user_input():

    virtual_address_size = int(input("请输入虚拟地址大小:"))

    physical_address_size = int(input("请输入物理地址大小:"))

    page_size = int(input("请输入虚页大小:"))

    cache_size = int(input("请输入cache大小:"))

    cache_block_size = int(input("请输入cache块大小:"))

    associativity = int(input("请输入相联度:"))

    # ... 其他参数

    # 进行参数验证和处理

    return (virtual_address_size, physical_address_size, page_size,

            cache_size, cache_block_size, associativity)

# 在程序的主要部分中调用此函数

def main():

    params = get_user_input()

    # 根据输入的参数设置数据结构和算法

    # ...

if __name__ == "__main__":

    main()

4:段式和页式的区别,如果改成段式存储,则如何实现段式首地址和偏移量?

段式和页式的区别:

页式存储:页机械地划分为大小相同的块。页式管理是以定长页面进行存储管理的方式。


段式存储:段会按程序逻辑划分成的相对独立可变长的块。段式管理是把主存按段分配的存储管理方式。

整体区别如下图所示。

如果改为段式存储,如何实现段式首地址和偏移量:

  1. 段表的构建:
    段表可以用数组或者列表实现,数组的索引或列表的位置可以用作段号。
    每个表项 = 段基址 + 段长度。
    (1)段基址:段在内存中的起始物理地址。
    (2)段长度:段在内存中的长度。
  2. 地址转换:
    虚拟地址由两部分组成:段号和段内偏移量。
    地址转换过程需要三个步骤,分别是:定位段、检查越界、计算物理地址。
    (1)定位段:使用段号从段表中查找到相应的段基址和段长度。
    (2)检查越界:检查偏移量是否超过了段长度。
    (3)计算物理地址:将段基址和偏移量相加,得到物理地址。
  3. 参考代码如下所示:

class Segment:

    def __init__(self, base, length):

        self.base = base

        self.length = length

def create_segment_table():

    # 示例:创建包含几个段的段表

    return [Segment(1000, 300), Segment(2000, 400), Segment(3000, 500)]

def translate_address(segment_table, segment_number, offset):

    if segment_number >= len(segment_table):

        raise ValueError("无效的段号")

   

    segment = segment_table[segment_number]

    if offset >= segment.length:

        raise ValueError("偏移量越界")

    return segment.base + offset

# 示例使用

segment_table = create_segment_table()

physical_address = translate_address(segment_table, 1, 50)  # 段号1,偏移量50

print("物理地址:", physical_address)

四、实验总结

1:虚拟存储器是存储器的逻辑模型,借助于磁盘等辅助存储器来扩大主存容量,为更大或更多的程序所使用。

2:物理地址由CPU地址引脚送出,用于访问主存的地址。

3:虚拟地址由编译程序生成,是程序的逻辑地址,其地址空间的大小受到辅助存储器容量的限制。

4:【主存-外存层次】和【cache-主存层次】用的地址变换映射方法和替换策略是相同的,都基于程序局部性原理(时间局部性 + 空间局部性)。


5:虚拟存储器的实现,基于基本信息传送单位、替换算法、地址映射、一致性问题。

6:替换算法主要分为以下几种:
    (1)LRU:近期最少使用算法。当需要替换一个页面时,选择最近最久未被使用的页面进行替换。它维护一个页面访问历史记录,并将最近被访问的页面置于队列的前面,而最久未被访问的页面在队列的末尾。当需要替换页面时,选择队列末尾的页面进行替换。
    (2)LFU:最不经常使用算法。当需要替换一个页面时,选择被访问次数最少的页面进行替换。它维护一个计数器来跟踪每个页面的访问次数,并选择访问次数最少的页面进行替换。
    (3)FIFO:先进先出算法。最早进入内存的页面会被最早替换出去。它使用一个队列来维护内存中的页面顺序,当需要替换页面时,选择队列中的最早进入的页面进行替换。
    (4)随机替换算法。当需要替换一个页面时,随机选择集合中的一个页面进行替换。
    (5)LFU + FIFO。

7:有效的页面置换算法可以显著减少缺页中断,提高系统效率。

五、代码修改

基于VA-Converting.cpp代码进行修改,实现【自行设计地址变换模拟器】。

#include "stdio.h"

#include "math.h"

#include"malloc.h"

#include "stdlib.h"

#include<iostream>

#include "math.h"

#define OK 1

#define OVERFLOW -1

#define ERROR -1

#define Max 5

typedef int status;

typedef int SElemType;

using namespace std;

int k=0;//记录缺页次数

/*--------------------栈及其操作---------------------*/

typedef struct {

    SElemType  *base; //栈底指针  

    SElemType   *top;  //栈顶指针

    int  count;    //栈的大小

}SqStack;

//构造空栈

status InitStack (SqStack &S){  

    S.base=(SElemType *)malloc(Max * sizeof(SElemType));

    if (!S.base)  return(OVERFLOW);

    S.count = 0;

    S.top = S.base;

    return(OK);

}

//入栈

status Push(SqStack &s,SElemType e)

{

    *s.top++=e;

    s.count++;

//  cout<<"插入"<<e<<endl;

    return OK;

}

//销毁栈

status DestroyStack(SqStack &S)

{

   

    S.top=NULL;

    S.base=NULL;

    delete[] S.base;

    S.count=0;

    return OK;

}

//判断栈是否为空

bool EmptyStack(SqStack s)

{

    if(s.count==0) return true;

    else          return false;

}

//是否已满

bool full(SqStack s)

{

    if(s.count==5) return true;

    return false;

}

//判断是否已经存在

int equeal(SqStack s,SElemType e)

{

    int num=s.count;

    if(EmptyStack(s)) return -1;

    for (int i=1;i<=num;i++)

    {

       if(*(s.top-i)==e)

           return i;

    }

    return -1;

}

//输出

void print(SqStack s){

    int a,i,num=s.count;

    //cout<<"有"<<num<<"个数"<<endl;

    for (i=0;i<num;i++)

    {

       a=*(s.base+i);

       cout<<a<<" ";

    }

    cout<<endl;

}

/*----------------页表---------------------*/

int pageLen=65536;//页面数

int l=2048;  //页面大小

struct page{

    int pageNum;

    int memNum;

}p[70000];

int initiate(){

    int i,j;

    for (i=0;i<pageLen;i++)

    {  

       j=rand()%11;

       p[i].pageNum=i;

       p[i].memNum=i+j;

    }

    return 1;

}

int locate(int n){

    for (int i=0;i<pageLen;i++)

    {

       if (p[i].pageNum==n)

       {

           return p[i].memNum;

       }

    }

    return -1;

}

//物理地址

int adress(){

    int pa,d,adr;

    cout<<"请输入逻辑地址:";

    cin>>adr;

    cout<<endl;

    pa=(int)adr/l;

    if (pa<0||pa>=l)

    {

       cout<<"越界"<<endl;

       return -1;

    }

    d=adr%l;

    int n=locate(pa);

    if (n!=-1)

    {

       int m=n*l+d;

       cout<<"其对应的页号是:"<<pa<<endl;

       cout<<"其对应的页内地址是:"<<d<<endl;

       cout<<"此页号地址对应的块号是:"<<n<<endl;

       cout<<"物理地址="<<n<<"*"<<l<<"+"<<d<<endl;

       cout<<"其物理地址为:"<<m<<endl;

       return m;

    }

    else{

       cout<<"此地址无对应项"<<endl;

       return -1;

    }

}

//随机替换算法

int randReplace(SqStack& s, SElemType e){

    int i;

    int num=equeal(s, e);

    cout<<"访问页面"<<e;

    if(!full(s)) {

        if (num==-1){

            cout<<",不存在此页号,"<<e<<"入栈"<<endl;

            k++;

            Push(s,e);

        }

    }

    else{

        if(num == -1){

            k++;

            cout<<",此页号不存在且栈满,随机替换栈中页面,并"<<e<<"入栈"<<endl;

            int randomIndex=rand()%Max;

            s.base[randomIndex]=e;

        }

    }

    return 1;

}

//执行随即替换算法

int begin(){

    int i,n,m;

    SElemType a[100];

    SqStack s;

    InitStack(s);

    cout<<"请输入页面数:";

    cin>>n;

    if (n>100){

       cout<<"输入的数值太大!!"<<endl;

       return 0;

    }

    cout<<"请输入页面号序列(0~~9):"<<endl;

    for(i=0;i<n;i++){

       cin>>m;

       if(m<0||m>9){

           cout<<"输入错误,请重新输入!!"<<endl;

           i--;

           continue;

       }

       a[i]=m;

    }

    for (i=0;i<n;i++)

    {

       randReplace(s,a[i]);

       cout<<"结果为:";

       print(s);

    }

    DestroyStack(s);

    cout<<"一共缺页"<<k<<"次"<<endl;

    return 1;

}

int Cachenum=64;

int CacheV=32;

int CACHE[65];

void cacheadress(int pad){

    int Index=pad/CacheV%Cachenum;

    int Offset=pad%CacheV;

    CACHE[Index]=pad/CacheV;

    cout<<"物理地址"<<pad<<"对应的cache索引为:"<<Index<<endl;

    cout<<"物理地址"<<pad<<"对应的cache块内地址为:"<<Offset<<endl;

}

int CacheHit(int pad){

    for(int i=0;i<Cachenum;++i){

       if(CACHE[i]==pad/CacheV){

           return 1;

       }

    }

    return -1;

}

int x;

int main(){

    int ok=0;

    initiate();

    while (ok!=3){

       cout<<"                       **********菜单***********"<<endl;

       cout<<"                             1--执行随即变换算法"<<endl;

       cout<<"                             2--地址变换    "<<endl;

       cout<<"                             3--退出        "<<endl;

       cout<<"                       *************************"<<endl;

       cout<<"请输入菜单号:";

       cin>>ok;

       switch (ok){

           case 1:

              begin();

              break;

           case 2:

              cout<<"页面大小是2kb"<<endl;

              cout<<"物理地址=其所对块号*页面大小+页内地址"<<endl;

              x=adress();

              if(CacheHit(x)==1)  cout<<"cache成功命中"<<endl;

              else  cout<<"cache命中失败"<<endl;

              cacheadress(x);

              break;

           default:

              break;

       }

    }

    return 1;

}

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

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

相关文章

easy Exsel导出

目录 一、首先引入依赖 二、然后封装一个VO 三、Controller层 四、Service实现类 引用样式 自适应列宽 自适应行高 五、测试 postman ​编辑 浏览器 异常 分配到这个任务了&#xff0c;写个小demo记录下&#xff0c;具体可参考EasyExcel官方文档 我用的是web上传…

redis数据安全(五)事务

一、概念&#xff1a; 1、介绍&#xff1a;Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令&#xff0c;一个事务中所有命令都会被序列化。在事务执行过程&#xff0c;会按照顺序串行化执行队列中的命令&#xff0c;其他客户端提交的命令请求不会插入到事务执行命…

css实现动态水波纹效果

效果如下&#xff1a; 外层容器 (shop_wrap)&#xff1a; 设置外边距 (padding) 提供一些间距和边距 圆形容器 (TheCircle)&#xff1a; 使用相对定位 (position: relative)&#xff0c;宽度和高度均为 180px&#xff0c;形成一个圆形按钮圆角半径 (border-radius) 设置为 50%&…

Linux编译器--gcc和g++使用

gcc和g使用 一、gcc/g的作用1.1 预处理1.2 编译1.3 汇编1.4 链接 二、静态库和动态库三、make/Makefile3.1 make/Makefile3.2 依赖关系和依赖方法3.3 多文件编译3.4 make原理3.5 项目清理 四、linux下的第一个小程序-进度条4.1 行缓冲区的概念4.2 \r和\n4.3 进度条代码 一、gcc…

rt-thread修改全局中断屏蔽函数,解决内核频繁关闭中断影响精密计时问题

带rtt-nano实时操作系统的小板子需要读取单总线设备&#xff0c;使用软件延时吧&#xff0c;总是由于时隙不精确&#xff0c;通信不稳定。按说不稳定情况也不频繁&#xff0c;但考虑到未来需要对上百、上千米外的单总线设备通信&#xff0c;开发的时候偷个懒&#xff0c;到应用…

Jmeter后置处理器——JSON提取器

目录 1、简介 2、使用步骤 1&#xff09;添加线程组 2&#xff09;添加http请求 3&#xff09; 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式&#xff0c;允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…

《Unix环境高级编程》第三版源代码编译报错汇总(WSL)

文章目录 Error: unable to disambiguate: -dylib (did you mean --dylib ?)undefined reference to majorerror: ‘FILE’ has no member named ‘__pad’; did you mean ‘__pad5’?error: ‘FILE’ has no member named ‘_flag’; did you mean ‘_flags’?error: ‘FIL…

AAAI 2024 | TEx-Face,5秒内按需生成照片级3D人脸

本文介绍一篇来自浙江大学ReLER实验室的工作&#xff0c;"Controllable 3D Face Generation with Conditional Style Code Diffusion"&#xff0c;目前该文已被AAAI 2024录用。 论文题目&#xff1a; Controllable 3D Face Generation with Conditional Style Code D…

(C语言)冒泡排序

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//实现buble_sort函数&#xff1b; void buble_sort(int arr[], int sz) {//初始化变量值&#xff1b;int i 0;//嵌套循环冒泡排序&#xff1b;//外层循环&…

adb、monkey的下载和安装

adb下载 官网网址&#xff1a;Downloads - ADB Shell 尽量不要下载最新的ADB Kits&#xff0c;因为兼容性可能不太好。 点击下载 ADB Kits 作者下载的版本是1.0.36 解压adb 到指定的目录即可。 然后把adb配置 环境变量。 检查adb是否安装成功

android 自定义八边形进度条

自定义八边形动画效果图如下 绘制步骤&#xff1a; 1.先绘制橙色底部八边形实心 2.黑色画笔绘制第二层&#xff0c;让最外层显示一条线条宽度即可 3.再用黄色画笔绘制黄色部分 4.使用渐变画笔根据当前进度绘制覆盖黄色部分 5.使用黑色画笔根据当前进度绘制刻度条 6.黑色画笔绘制…

C语言经典练习3——[NOIP2008]ISBN号码与圣诞树

前言 在学习C语言的过程中刷题是很重要的&#xff0c;俗话说眼看千遍不如手动一遍因为在真正动手去刷题的时候会暴露出更多你没有意识到的问题接下来我就为各位奉上两道我认为比较有代表性的题 1. [NOIP2008]ISBN号码 1.1 题目描述 每一本正式出版的图书都有一个ISBN号码与之对…

BKP备份寄存器读取

1.简介&#xff1a; BKP&#xff08;Backup&#xff09;备份寄存器是一种特殊的功能寄存器&#xff0c;用于存储某些设备的备份数据。这些数据通常是非常重要的&#xff0c;因此需要定期备份以防止意外丢失。 具体来说&#xff0c;BKP寄存器可以用于以下几种情况&#xff1a;…

100天精通鸿蒙从入门到跳槽——第6天:TypeScript 知识储备:类

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

保留图片原画质图片无损放大

在数字时代&#xff0c;图片的放大和缩放是常见的操作。然而&#xff0c;传统的图片放大方法往往会导致图片质量的损失&#xff0c;使得图片的细节和清晰度降低。为了解决这个问题&#xff0c;水印云推出了一项新的功能——无损放大&#xff0c;让你可以在不损失图片质量的情况…

精选100 GPTs深度解析专题

精选100 GPTs深度解析专题 背景 1月10日&#xff0c;GPT应用商店&#xff08;GPT Store&#xff09;的正式上线&#xff0c;GPT技术的应用已经呈现爆炸性增长。目前&#xff0c;市场上已经出现了超过300万种GPTs&#xff0c;应用领域涵盖图像生成、写作、效率提升、研究分析、编…

部署Sqli-labs靶场:一篇文章解析全过程

部署Sqli-labs靶场&#xff1a;一篇文章解析全过程 0x01 前言 Sqli-labs是一个在线的SQL注入练习平台&#xff0c;提供了一系列关卡供用户练习SQL注入的技巧和防范方法。在这个平台上&#xff0c;用户可以尝试注入攻击&#xff0c;并测试自己的技能和工具&#xff0c;同时也可…

python数字图像处理基础(六)——模板匹配、直方图

目录 模板匹配概念单对象模板匹配多对象模板匹配 直方图1.查找直方图2.绘制直方图3.掩膜的应用 模板匹配 概念 模板匹配和卷积原理很像&#xff0c;模板在原图像上从原点开始滑动&#xff0c;计算模板与图像被模板覆盖的地方的差别程度&#xff0c;这个差别程度的计算方法在o…

CS8370错误,这是由于使用了C# 7.3中不支持的功能

目录 背景: 第一种方法: 第二种办法: 背景: 在敲代码的时候&#xff0c;程序提示报错消息提示:CS8370错误&#xff0c;那么这是什么原因导致的&#xff0c;这是由于使用了C# 7.3中不支持的功能&#xff0c;不支持该功能&#xff0c;那就是版本太低我们就需要升级更高的版本&…

DAY03_Spring—自动装配注解模式优化XML文件

目录 1 Spring注解模式1.1 自动装配1.1.1 说明1.1.2 配置规则 1.2 注解模式1.2.1 关于注解的说明1.2.2 注解使用原理1.2.3 编辑配置文件1.2.4 属性注解 1.3 实现MVC结构的纯注解开发1.3.1 编写java代码1.3.2 编辑xml配置文件1.3.3 编写测试类1.3.4 关于注解说明1.3.5 关于Sprin…