基础知识
类型转换
c语言风格的类型转换
- (type)expression
- type(expression)
c++中有4个类型转换符
- static_cast
- 对比dynamic_cast缺少运行时检测
- 不能交叉转换(不是同一继承体系的,无法转换)
- 常用于基本数据类型的转换、非const转成const
- dynamic_cast
- 一般用于多态(virutal)类型的转换,有运行时安全检测
- 和(type)expression不一样,多了运行时安全检测
- 如果安全则将值直接返回,如果不安全则返回null
- reinterpret_cast
- 属于比较底层的强制转换,没有任何类型检测和格式转换,仅仅是简单的二进制数据拷贝
#include <iostream>
using namespace std;
#pragma warning(disable:4996)
int main() {
//0A 00 00 00
int a =10;
//00 00 00 00 00 00 24 40
//double d=a;
//0A 00 00 00 cc cc cc cc
double d = reinterpret_cast<double&>(a);
cout << sizeof(a) << endl;
cout << sizeof(d) << endl;
getchar();
return 1;
}
- const_cast
- 一般用于去除const属性,将const转成非const
- 和(type)expression一模一样
使用格式
- xx_cast<type>(expression)
页
- Linux系统分配真正内存时,用页作为单位,一次最少提供一页的真实内存空间
- 方法
//头文件
#include <unistd.h>
//函数,返回值是内存分页大小
static __inline__ int getpagesize(void) {
return sysconf(_SC_PAGESIZE);
}
memcpy
- 函数
void *memcpy(void *str1, const void *str2, size_t n)
- 参数
- str1:用于存储复制内容的目标
- str2:要复制的数据源
- n:要被复制的字节数
通俗讲:将str2的n个数据复制给str1
mmap
- 函数
void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t of fset);
-
参数
- add:地址,当为NULL的时候,由系统分配
- len:内存的大小
- prot:
- PROT_EXEC内容可以被执行;
- PROT_READ:内容可以被读取;
- PROT_WRITE:内容可以被写入;
- PROT_NONE:内容不可访问
- flags:MAP_SHARED:共享;MAP_PRIVATE:私用;MAP_ANONYMOUS:匿名映射(不基于文件),fd传入-1
- fd:打开文件的句柄
- fset:偏移大小,必须是4k的整数倍,一个物理页映射是4k
-
原理
通过mmap映射文件的一块到用户空间,然后通过mmap返回的指针操作mmap映射的用户空间,相当于同时操作了文件
实现步骤
- 1、通过mmap获取到文件的句柄
/**
* 默认最小的增长大小
*/
static int DEFAULT_INCREASE_SIZE = getpagesize() * 128;
FileLogger::FileLogger(const char *logPath, int maxFileSize) {
this->logPath = (char *) malloc(strlen(logPath) + 1);
memcpy(this->logPath, logPath, strlen(logPath) + 1);
this->maxFileSize = maxFileSize;
// 计算每次映射多大数据
increaseSize = maxFileSize / REMMAP_TIMES;
if (mmapSize < DEFAULT_INCREASE_SIZE) {
increaseSize = DEFAULT_INCREASE_SIZE;
} else if (increaseSize % getpagesize() != 0) {
// 保证是页的整数倍
increaseSize = (increaseSize / getpagesize() + 1) * getpagesize();
}
// 读取到整个文件的大小
int fileSize = getLogFileSize();
if (fileSize <= 0) {
mmapSize = increaseSize;
// 打开映射文件
mmapFile(0, mmapSize);
} else {
mmapSize = fileSize;
mmapFile(0, fileSize);
if (dataPos >= maxFileSize) {
// 释放之前映射过的内存
if (mmapPtr != NULL) {
munmap(mmapPtr, mmapSize);
}
}
}
}
void FileLogger::mmapFile(int start, int end) {
// 打开文件
int logFd = open(logPath, O_RDWR | O_CREAT, S_IRWXU);
// 给文件新增大小空间
ftruncate(logFd, mmapSize);
int size = end - start;
mmapPtr = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, logFd, start);
// 关闭文件
close(logFd);
}
- 2、获取文件的大小
int FileLogger::getLogFileSize() {
//1、打开文件
FILE *fp = fopen(logPath, "r");
if (fp == NULL) {
return 0;
}
fseek(fp, 0L, SEEK_END);
//2、获取文件大小
int size = ftell(fp);
//3、关闭文件
fclose(fp);
return size;
}
- 3、析构函数:释放映射过得内存
FileLogger::~FileLogger() {
// 释放映射过的内存
if (mmapPtr != NULL) {
munmap(mmapPtr, mmapSize);
}
}
- 4、写文件
void FileLogger::writeData(const char *data, int dataLen) {
if (dataPos + dataLen > mmapSize) {
if (dataPos + dataLen > maxFileSize) {
int maxSize = dataPos + dataLen;
if (maxSize % getpagesize() != 0) {
maxSize = ((maxSize / getpagesize()) + 1) * getpagesize();
}
increaseSize = maxSize - mmapSize;
}
// 释放之前映射过的内存
if (mmapPtr != NULL) {
munmap(mmapPtr, mmapSize);
}
mmapSize += increaseSize;
mmapFile(0, mmapSize);
}
// 把数据写入映射区域 (文件)
memcpy(mmapPtr + dataPos, data, dataLen);
dataPos += dataLen;
// memcpy(mmapPtr + (mmapSize - DEFAULT_POSITION_SIZE - 1), &dataPos, DEFAULT_POSITION_SIZE);
}
- 5、文件读取
FileLogger *fileLogger = (FileLogger *) nativePtr;
if (fileLogger != NULL) {
char *mmapPtr = fileLogger->readLog();
jstring data=env->NewStringUTF(mmapPtr);
return data;
}
网友评论