【C语言进阶】内存函数和结构体内存对齐

目录

  • 一.strerror函数
      • 1.错误码变量errno
      • 2.strerror函数的使用
      • 3.perror函数
    • 二.memcpy函数
        • 1.函数介绍
        • 2.模拟实现
      • 三.memmove函数
          • 1.函数介绍
          • 2.模拟实现
        • 四.结构体的内存对齐

一.strerror函数

1.错误码变量errno

规定:
C语言库函数如果出现运行错误,会将对应错误信息的错误码保存到全局变量errno(头文件为errno.h)中.

2.strerror函数的使用

我们先来看strerror函数的原型:

char *strerror( int errnum );

向函数传入错误代码,他可以将错误码翻译为错误信息并将信息字符串的首元素地址返回
这里我们引入文件管理的函数来演示strerror函数的效果:

FILE *fopen( const char *filename, const char *mode );

如果打开文件成功则返回有效的指针,否则返回空指针。
演示代码如下:

#include 

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");//只读文件
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);//关闭文件
	return 0;
}

在我创建的项目下并没有test.txt,这个错误会转换为错误码并且存在errno变量中,strerror函数则可以解析这个错误码。
打印结果如下:
【C语言进阶】内存函数和结构体内存对齐_第1张图片

3.perror函数

除strerror函数外还要介绍一个函数:perror直接打印错误信息,打印之前会先打印自定义信息(头文件stdio)。
对比上文:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fclose(pf);

	return 0;
}

在这里插入图片描述

二.memcpy函数

1.函数介绍

在之前我们学习过strcpy和strncpy函数,他们是专门针对字符串拷贝的函数。而其他类型则不能使用,为了能够拷贝多种数据类型,C语言有这样的内存函数memcpy,memcpy函数则是以字节为单位拷贝数据。
函数原型:

void *memcpy( void *dest, const void *src, size_t count );

注意事项:

  1. 函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置.
  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来。(因为不是字符串函数)。
  3. 如果dest和src有任何的重叠,则可能会出现错误。
2.模拟实现
void* my_memcpy(void* p1, const void* p2, size_t num)
{
	assert(p1 && p2);
	void* ret = p1;
	while (num--)
	{
		*(char*)p1 = *(char*)p2;
		p1 = (char*)p1 + 1;
		p2 = (char*)p2 + 1;
	}
}

int main()
{
	int arr1[] = { 1,2,9,4,8 };
	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 12);
	return 0;
}

三.memmove函数

1.函数介绍

函数原型

void *memmove( void *dest, const void *src, size_t count );

注意事项

  1. 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
  2. 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
2.模拟实现
void* my_memmove(void* p1, const void* p2, size_t num)
{
	void* ret = p1;
	if (p2 > p1)//前--->后
	{
		while (num--)
		{
			*(char*)p1 = *(char*)p2;
			p1 = (char*)p1 + 1;
			p2 = (char*)p2 + 1;
		}
	}
	else//后--->前
	{
		while (num--)
		{
			*((char*)p1 + num) = *((char*)p2 + num);
		}
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9};
	int arr2[20] = { 0 };
	my_memmove(arr1, arr1 + 2, 16);
	return 0;
}
四.结构体的内存对齐

讲解内存对齐之前我们先看一个小问题:

#include 

 struct AB{
	int a;
	char b;
	short c;
	short d;
};

int main()
{
	printf("%d\n", sizeof(struct AB));
	return 0;
}

上面的代码结果是多少,很多人会这样算:4+1+2+2=9.
但是其实结果是:
【C语言进阶】内存函数和结构体内存对齐_第2张图片

这里就需要学习关于结构体的内存对齐问题,结构体在内存的存储并不是想数组那样连续的内存存放。而是与编译环境的对齐数有关而且结构体在内存中的存放有偏移量的概念偏移量从起始地址开始从0开始一字节加一
有如下规定:

  1. 结构体的第一个成员,对齐到结构体在内存中存放位置的0偏移处
  2. 从从第二个成员开始,每个成员都要对齐到(一个对齐数) 的整数倍处对齐数: 结构体成员自身大小和默认对齐数的较小值默认对齐
  3. 结构体的总大小,必须是所有成员的对齐数中最大对齐数的整数倍
  4. 如果结构体中嵌套了结构体成员,要将嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处。结构体的总大小必须是最大对齐数整数倍,这里的最大对齐数是: 包含嵌套结构体成员中的对齐数,的所有对齐数中的最大值。

举几个例子:

eg1:对齐数为4的环境下:
【C语言进阶】内存函数和结构体内存对齐_第3张图片
eg2:对齐数为8的环境下:
【C语言进阶】内存函数和结构体内存对齐_第4张图片

你可能感兴趣的:(C,c语言,开发语言,c++)