一个基于单片机内存管理-开源模块

概述

        此模块是一位大佬写的应用于单片机内存管理模块mem_malloc,这个mem_malloc的使用不会产生内存碎片,可以高效利用单片机ram空间。

源码仓库:GitHub - chenqy2018/mem_malloc

mem_malloc介绍

一般单片机的内存都比较小,而且没有MMU,malloc 与free的使用容易造成内存碎片。而且可能因为空间不足而分配失败,从而导致系统崩溃,因此应该慎用,或者自己实现内存管理。mem_malloc就是一个不会产生内存碎片的、适合单片机使用的内存管理模块。其与使用malloc的区别如:

算法原理:定义一个数组作为动态分配的堆空间,低地址空间保存管理数据,高地址空间实际分配给用户的缓存(类似堆栈使用,分配是往中间靠拢),free时移动高地址用户空间(以时间换空间),使得未使用的空间都是连续的。

一、开发环境

1、硬件平台
     STM32F401CEU6
     内部Flash : 512Kbytes,SARM : 96 Kbytes

二、STM32CubeMx配置

 2.1、系统时钟配置

2.2、下载调试配置

2.3、usart1配置

2.4、生成代码

2.5、打开工程并编译

三、编码 

1、usart.c添加打印

/* USER CODE BEGIN 1 */
#include "stdio.h"
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}
 
int fgetc(FILE * f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/* USER CODE END 1 */

记得把这个勾上,不然 uart 打不出来。 

在根目录创建malloc文件夹,将下载好的mem_malloc代码,分别把mem_malloc.c、mem_malloc.h复制到工程目录下,并添加到工程里:

然后进行编译,编译后会报以下错误:莫慌一个个解决它即可。


 

这份代码在不同编译器下编译情况不同。gcc下编译不会报错,在keil下编译报如上错误。

keil编译器更严格些。

原因是对void*类型 "mem_block结构体的mem_ptr成员"进行了位移,即mem_block->mem_ptr - offset ,而编译器不知道你一个位移是多大,取决于mem_ptr实际的类型。如果是(char*)型,那么位移时按一个字节位移,如果是(int*)型,那么位移时按4个(32位机)字节位移,因此编译器不清楚属于哪一种,会报错。

把相关报错代码改成如下:

再次编译就正常了。

mem_malloc.h:

#ifndef __MEM_MALLOC_H__
#define __MEM_MALLOC_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h> 
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#pragma pack(1)
typedef struct mem_block{ 
    void			*mem_ptr;  
    unsigned int	mem_size; 
    unsigned int	mem_index;    
}mem_block;
#pragma pack()

#define MEM_SIZE        256


void print_mem_info(void);
void print_hex(char *data, int len);
void print_mem_hex(int size);
int mem_malloc(unsigned int msize);
int mem_realloc(int id, unsigned int msize);
void *mem_buffer(int id);
int mem_free(int id);


#ifdef __cplusplus
}
#endif

#endif

mem_malloc.c:


#include "mem_malloc.h"

static unsigned int sum = 0;
static char			mem[MEM_SIZE];

#define DEBUG_EN	0
#define MEM_START	&mem[0]
#define MEM_END		&mem[MEM_SIZE]  
#define BLK_SIZE	sizeof(mem_block) 

void print_mem_info(void){
	printf("------------mem_info--------------\n");
	printf("sizeof(mem_block)=%d\n", BLK_SIZE);
	printf("MEM_START = %d(0x%x)\n", (int)MEM_START, (int)MEM_START);
	printf("MEM_END   = %d(0x%x)\n", (int)MEM_END, (int)MEM_END);
	printf("MEM_SIZE  = %d(0x%x)\n", (int)MEM_SIZE, (int)MEM_SIZE);
	printf("----------------------------------\n");	
}

void print_hex(char *data, int len){
	for(int i=0; i<len; i++){
		printf("%02x ", (unsigned char)data[i]);
		if((i+1)%12 == 0)   printf("\n");
	}
	printf("\n");
}

void print_mem_hex(int size){
	print_hex(mem, size);
}

int mem_malloc(unsigned int msize){
	unsigned int all_size = msize + sizeof(mem_block);
	mem_block tmp_blk;
	if(msize == 0) return 0;
	if(sum){
		mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*(sum-1));
		int free_blk = (char *)ptr_blk->mem_ptr-(MEM_START + BLK_SIZE*sum);
		if(all_size <= free_blk){
			tmp_blk.mem_ptr = (char *)ptr_blk->mem_ptr - msize;
			tmp_blk.mem_size = msize;
			tmp_blk.mem_index = ptr_blk->mem_index + 1;
			memcpy(MEM_START + BLK_SIZE*sum, &tmp_blk, BLK_SIZE);
			sum = sum + 1;
		#if DEBUG_EN
			printf("mem_ptr = 0x%x\n", (int)tmp_blk.mem_ptr);
			printf("mem_size = 0x%x\n", tmp_blk.mem_size);
			printf("mem_index = 0x%x\n", tmp_blk.mem_index);
		#endif
			return tmp_blk.mem_index;
		}
	}else{
		if(all_size <= MEM_SIZE){
			tmp_blk.mem_ptr = MEM_END - msize;
			tmp_blk.mem_size = msize;
			tmp_blk.mem_index = 1;
			memcpy(MEM_START, &tmp_blk, BLK_SIZE);
			sum = 1;
        #if DEBUG_EN
			printf("mem_ptr = 0x%x\n", (int)tmp_blk.mem_ptr);
			printf("mem_size = 0x%x\n", tmp_blk.mem_size);
			printf("mem_index = 0x%x\n", tmp_blk.mem_index);
        #endif
			return 1;
		}
	}
	return 0;
}

int mem_realloc(int id, unsigned int msize){
	for(int i=0; i<sum; i++){
		mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*i);
		if(id == ptr_blk->mem_index){
			int free_blk = (char *)ptr_blk->mem_ptr-(MEM_START + BLK_SIZE*sum);
			int old_size = ptr_blk->mem_size;
			int offset = msize - old_size;
			int move_size = 0; 
			int n = sum - i;
			mem_block *ptr_tmp;
			if(offset == 0){
				return 0;
			}else if(offset < 0){
				offset = old_size - msize;
				for(int j=1; j<n; j++){
					ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
					move_size += ptr_tmp->mem_size;
				}
				if(n == 1){
					ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*i);
				}
				move_size += msize;
				char *dst_addr = (char *)ptr_tmp->mem_ptr + move_size + offset - 1;
				char *src_addr = (char *)ptr_tmp->mem_ptr + move_size - 1;
				for(int j=move_size; j>0; j--){
					*dst_addr-- = *src_addr--;
				}
				memset(src_addr, 0, offset+1);
				for(int j=0; j<n; j++){
					ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
					//ptr_tmp->mem_ptr += offset;
					ptr_tmp->mem_ptr = (char *)ptr_tmp->mem_ptr + offset;
					if(j == 0){
						ptr_tmp->mem_size = msize;
					}
				}
				return 1;
			}else{
				if(offset <= free_blk){
					for(int j=1; j<n; j++){
						ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
						move_size += ptr_tmp->mem_size;
					}
					if(n == 1){
						ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*i);
					}
					move_size += old_size;
					char *dst_addr = (char *)ptr_tmp->mem_ptr - offset;
					char *src_addr = (char *)ptr_tmp->mem_ptr;
					for(int j=0; j<move_size; j++){
						*dst_addr++ = *src_addr++;
					}
					for(int j=0; j<n; j++){
						ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
						//ptr_tmp->mem_ptr -= offset;
						ptr_tmp->mem_ptr = (char *)ptr_tmp->mem_ptr - offset;
						if(j == 0){
							ptr_tmp->mem_size = msize;
						}
					}
					return 1;				
				}
			}
		}
	}
	return 0;
}

void *mem_buffer(int id){
	for(int i=0; i<sum; i++){
		mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*i);
		if(id == ptr_blk->mem_index){
			return ptr_blk->mem_ptr;
		}
	}
	return NULL;
}

int mem_free(int id){
	for(int i=0; i<sum; i++){
		mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*i);
		if(id == ptr_blk->mem_index){
			mem_block *ptr_old;
			if(i != (sum-1)){
				int offset = ptr_blk->mem_size;
				int move_size = 0; 
				int n = sum - i;
				mem_block *ptr_tmp;
				for(int j=1; j<n; j++){
					ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
					move_size += ptr_tmp->mem_size;
				}
				//memmove();
				char *dst_addr = (char *)ptr_tmp->mem_ptr + move_size + offset - 1;
				char *src_addr = (char *)ptr_tmp->mem_ptr + move_size - 1;
				for(int j=move_size; j>0; j--){
					*dst_addr-- = *src_addr--;
				}
				memset(src_addr, 0, offset+1);
				for(int j=0; j<(n-1); j++){
					ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
					ptr_old = (mem_block *)(MEM_START + BLK_SIZE*(i+j+1));
					memcpy(ptr_tmp, ptr_old, BLK_SIZE);
					//ptr_tmp->mem_ptr += offset;
					ptr_tmp->mem_ptr = (char *)ptr_tmp->mem_ptr + offset;
				}
			}else{
				ptr_old = (mem_block *)(MEM_START + BLK_SIZE*i);
				memset(ptr_old->mem_ptr, 0, ptr_old->mem_size);
			}
			memset(ptr_old, 0, BLK_SIZE);
			sum = sum - 1;
			return 1;
		}
	}
	return 0;
}

main.c文件,在作者提供的基础上做些修改,如下所示:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "mem_malloc.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
char mem_id[20]={0}; //20块内存块
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
void test_malloc(int i, int size)
{
	printf("------test_malloc-------\n");
	mem_id[i] = mem_malloc(size);
	
	if(mem_id[i] == 0) {
		printf("malloc --- fail\n");
		printf("size=%d\n", size);
		return ;
	}

	char *p = mem_buffer(mem_id[i]);
	memset(p, i, size);
	printf("p = 0x%x, i=%d, id=%d, size=%d\n", (int)p, i, mem_id[i], size);
	print_mem_hex(MEM_SIZE);
}

void test_buffer(int i, int size)
{
	printf("------test_buffer-------\n");
	printf("i=%d, id = %d, size=%d\n", i, mem_id[i], size);
	char *buf_p = mem_buffer(mem_id[i]);
	
	if(buf_p == NULL) {
		printf("test_buffer---fail\n");
		return ;
	}
	
	memset(buf_p, 0xF0 + i, size);
	print_mem_hex(MEM_SIZE);
}

void test_realloc(int i, int size)
{
	printf("------test_realloc-------\n");
	printf("i=%d, id = %d, size=%d\n", i, mem_id[i], size);
	int rea_p = mem_realloc(mem_id[i], size);
	
	if (rea_p == NULL) {
		printf("test_realloc---fail\n");
		return ;
	}
	
	char *buf_p = mem_buffer(mem_id[i]);
	memset(buf_p, 0xA0 + i, size);
	print_mem_hex(MEM_SIZE);
}

void test_free(int i)
{
	printf("------test_free-------\n");
	printf("i=%d, id = %d\n", i, mem_id[i]);
	
	if(mem_free(mem_id[i]))
		print_mem_hex( MEM_SIZE);
}
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	printf("heiheihei\r\n");
	
	print_mem_info();   // 打印内存信息
	test_malloc(1, 10); // 给申请一块10个字节的内存,标记内存块id为1
	test_malloc(2, 8); // 给申请一块8个字节的内存,标记内存块id为2
	test_malloc(3, 20); // 给申请一块20个字节的内存,标记内存块id为2

	test_free(2);  // 释放id为2的内存块的内存

	test_malloc(4, 70); // 申请一块70个字节的内存

	test_free(1);       // 释放id为1的内存块内存

	test_buffer(3, 20); // 获取id为3的内存块地址,并往这个内存块重新写入0xf0+i的数据

	test_realloc(3, 10); // 重新分配内存,并往这个内存块重新写入0xa0+i的数据

	for(int i=0; i<10; i++) { // 释放所有内存块内存,已释放的不再重新释放
		test_free(i);	
	}
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_Delay(1000);
	  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	  printf("hahaha\r\n");
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

四、运行结果及解析:

 

        这里设定一个256字节的数组作为堆空间使用。其中数组前面存放的是申请到的内存块的信息,包括内存块地址、大小、索引信息,这三个数据各占4个字节,共12个字节。这里有设计到一个大小端模式的问题,STM32平台为小端模式,即数据的低位存储在内存的低地址中。

申请的内存块从256字节的尾部开始分配,再次申请的内存块依次往前移,释放的内存,则整体内存块往后移动,内存块之前不留空隙,即不产生内存碎片。

五、总结

        好了,讲解完毕,希望能帮助到需要的同仁们,感谢参阅,一天进步点,加油加油!!!^_^

参考文章:一个应用于单片机的内存管理模块

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单调栈基础题

739. 每日温度 问题描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。…

模型融合1

一、模型融合:与集成算法一样,都是训练多个评估器,并将多个评估器以某种方式结合起来解决问题的机器学习办法。但是区别是模型融合能够再经典集成模型的基础上进一步提升分数,使用模型融合ji融合:与集成算法一样,都是训练多个评估器,并将多个评估器以某种方式结合起来解…

[SystemVerilog]常见设计模式/实践

常见设计模式/实践 RTL 设计&#xff08;尤其是 ASIC&#xff09;的最终目标是制作出最小、最快的电路。为此&#xff0c;我们需要了解综合工具如何分析和优化设计。此外&#xff0c;我们还关注仿真速度&#xff0c;因为等待测试运行实际上是在浪费工程精力。虽然综合和仿真工…

java项目实战之图书管理系统(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.背景 图书管理系统是一种用于管理图书…

STC89C52学习笔记(十二)

STC89C52学习笔记&#xff08;十二&#xff09; 一、AD/DA 1.定义 AD能够将模拟信号转化为数字信号&#xff0c;DA能够将数字信号转化为模拟信号。 2.两种类型的DA转换器 &#xff08;1&#xff09;PWM型DA滤波器 由于PWM是通过脉冲调制的方法来调整的&#xff0c;低通滤…

【机器学习】数学基础详解

线性代数&#xff1a;构建数据的骨架 数学对象 标量&#xff08;Scalar&#xff09; 标量是最基本的数学对象&#xff0c;代表了单个的数值&#xff0c;无论是整数还是实数。在机器学习中&#xff0c;标量可以用来表示一个模型的单个参数&#xff0c;如偏差&#xff08;bias&…

学习大数据,所需要的java(Maven)基础(2)

文章目录 Maven核心概念统一管理目标jar包的版本仓库生命周期插件和目标 继承为什么需要继承机制创建父工程在子工程中引用父工程在子工程中引用父工程在父工程中管理依赖 聚合为什么要使用聚合如何配置聚合 Maven酷站Maven生产环境所遇到的问题jar未下载完成jar包冲突问题 Mav…

ActiveMQ入门案例(queue模式和topic模式)

目录 前言&#xff1a;为什么使用消息中间件&#xff1f; 异步通信 缓冲 解耦 前提&#xff1a;安装并启动activemq 一、点对点&#xff08;point to point&#xff0c; queue&#xff09; 1.1 创建maven项目 1.2 Pom依赖 1.2 JmsProduce 消息生产者 1.3 JmsConsumer…

伺服驱动器算法入门的一些建议和书籍推荐

希望此篇文章对想从事伺服驱动器的研发工作的一些刚刚入门的同学一些建议。 针对伺服驱动器的研发工作涉及的知识和需要掌握的技能主要分为两部分&#xff0c;第一是原理部分、第二是工程实践部分。原理部分的学习在此主要推荐大家查看一些入门书籍&#xff0c;本文章中也对书籍…

iOS------SDWebImage源码

一&#xff0c;简介 一个异步图片下载及缓存的库 特性&#xff1a; 一个扩展UIImageView分类的库&#xff0c;支持加载网络图片并缓存图片异步图片下载器异步图片缓存和自动图片有效期限管理支持GIF动态图片支持WebP背景图片减压保证同一个URL不会再次下载保证无效的URL不会…

Linux 目录结构与基础查看命令

介绍 目录结构如下 /bin&#xff1a;存放着用户最经常使用的二进制可执行命令&#xff0c;如cp、ls、cat等。这些命令是系统管理员和普通用户进行日常操作所必需的。 /boot&#xff1a;存放启动系统使用的一些核心文件&#xff0c;如引导加载器&#xff08;bootstrap loader…

Linux学习笔记之9(消息队列)

Linux learning 1、引言2、创建一个消息队列3、发送和接受消息3.1、发送消息3.1、接收消息 4、删除一个消息队列5、例程 1、引言 消息队列&#xff08;message queue&#xff09;也是进程之间通信的一种方式&#xff0c;相比于共享内存的通信方式&#xff0c;消息队列也有类型…

构建BTI的编译工具支持

BTI分支目标识别精讲与实践系列 思考 1、什么是代码重用攻击&#xff1f;什么是ROP攻击&#xff1f;区别与联系&#xff1f; 2、什么是JOP攻击&#xff1f;间接分支跳转指令&#xff1f; 3、JOP攻击的缓解技术&#xff1f;控制流完整性保护&#xff1f; 4、BTI下的JOP如何…

2024 Guitar Pro 8.1.2-27 (x64) win/mac中文激活版破解版

吉他爱好者必备神器&#xff1a;Guitar Pro v8.1.1 Build 17深度解析 随着数字音乐制作和学习的日益普及&#xff0c;越来越多的吉他爱好者开始寻找能够帮助他们提升技能、创作音乐的专业工具。在众多吉他制作软件中&#xff0c;Guitar Pro因其强大的功能和易用的界面备受推崇…

001vscode为什么设置不了中文?

VSCode中文插件安装 在VSCode中设置中文的首要步骤是安装“Chinese (Simplified) Language Pack for Visual Studio Code”扩展插件。这一过程十分简单&#xff0c;只需打开VSCode&#xff0c;进入扩展市场&#xff0c;搜索“ Chinese (Simplified) Language Pack ”然后点击…

EasyUI Jquery 学习笔记 —— Window(窗口)详细版

1. Window(窗口) 1.1 Messager 消息框 通过 $.messager.defaults 重写默认的 defaults。 消息框(messager)提供不同样式的消息框,包括警示(alert)、确认(confirm)、提示(prompt)、进展(progress)等等。所有的消息框都是异步的。用户可以在与消息框交互后使用回…

初识C++ · 类和对象(中)

目录 1 类的6个默认成员函数 2 构造函数 3 析构函数 3 拷贝构造函数 1 类的6个默认成员函数 class Date { public:private:}; 这是一个空类&#xff0c;试问里面有什么&#xff1f; 可能你会觉得奇怪&#xff0c;明明是一个空类&#xff0c;却问里面有什么。其实一点也不…

HLOOKUP函数结合数据验证实现的动态图表

小伙伴们&#xff0c;大家好啊&#xff01;今天我们分享一个使用HLOOKUP函数结合数据验证实现的动态图表技巧&#xff1b; 接下来我们具体说说操作步骤吧。 步骤1&#xff1a;选中A列的【路口车辆通过数】单元格区域&#xff0c;复制粘贴后到右边的空白区域&#xff0c;如I列…

通过调用Vcenter-Api获取Vcenter中服务器信息

通过调用Vcenter-Api获取Vcenter中服务器信息 文章目录 通过调用Vcenter-Api获取Vcenter中服务器信息1. 获取Vmware API帮助文档2. 获取访问凭证3. 获取服务器清单4. 获取服务器更多信息5. 获取虚机更多信息6. 获取磁盘信息7. 获取操作系统相关 1. 获取Vmware API帮助文档 htt…

建模设计软件 Archicad 27 for mac激活版

在建筑设计领域&#xff0c;每一次技术的革新都意味着设计效率和质量的飞跃。Archicad 27 for Mac&#xff0c;就是这样一款引领行业变革的设计软件。 Archicad 27凭借出色的性能优化和强大的功能更新&#xff0c;为Mac用户带来了前所未有的建筑设计体验。它支持BIM&#xff08…