03-C lenguaje avanzado: simula la realización de funciones de operación de memoria (memmove y memcpy)


memcpy y memmove no son funciones de manipulación de cadenas, sino funciones de manipulación de memoria, y hay muchas situaciones en las que la memoria se copia y se mueve. Las siguientes dos funciones se implementan mediante simulación para discutir las diferentes situaciones de las dos piezas de memoria y la manipulación de memoria Funciones La diferencia es que el contenido de esta sección es difícil de expresar claramente con palabras, si tienes alguna duda o no entiendes, ¡puedes dejar un mensaje para discutir!

1.La diferencia entre memcpy y memmove

Primero, consulte la documentación oficial del lenguaje C para distinguir la diferencia entre las dos funciones. Para la traducción al inglés con software de traducción, puede ver directamente el resumen.
Inserte la descripción de la imagen aquí
Traducción:

  • Copie el valor de num bytes de la ubicación apuntada por la fuente directamente al bloque de memoria apuntado por el destino.
  • El tipo subyacente del objeto al que apuntan el puntero de origen y el puntero de destino no tiene nada que ver con esta función; el resultado es una copia binaria de los datos.
  • Esta función no comprueba ningún carácter nulo de terminación en el archivo de origen; siempre copia num bytes con precisión.
  • Para evitar el desbordamiento, el tamaño de la matriz al que apuntan los parámetros de origen y destino debe ser de al menos num bytes y no debe superponerse (memmove es un método más seguro para superponer bloques de memoria).
    Inserte la descripción de la imagen aquí
    Traducción:
  • Copie el valor de num bytes de la ubicación apuntada por el origen al bloque de memoria apuntado por el destino. La copia se realiza como si se utilizara un búfer intermedio, lo que permite que el destino y el origen se superpongan.
  • El tipo básico del objeto al que apuntan los punteros de origen y destino no tiene nada que ver con esta función; el resultado es una copia binaria de los datos.
  • Esta función no comprueba ningún carácter nulo de terminación en el archivo de origen; siempre copia num bytes con precisión.
    Para evitar el desbordamiento, el tamaño de la matriz a la que apuntan los parámetros de origen y destino debe ser de al menos num bytes.
    Resumen: En pocas palabras, la diferencia entre los dos es que memcpy no considera la superposición de memoria, mientras que memmove considera la superposición de memoria. Las siguientes son varias formas superpuestas de bloques de memoria
    Inserte la descripción de la imagen aquí

2. Simular la realización de memcopy

Primer constructor

  • el tipo de retorno de memcpy es nulo *
  • Copie src a dst, por lo que src es de tipo constante
//1.模拟实现memcpy
void * my_memcpy(void * dst, const void * src, size_t num)
{
    
    
	//判断指针合法性
	assert(dst != NULL);
	assert(src != NULL);

	//将void *强制类型转为char *,方便按字节拷贝
	char *_dst = (char *)dst;
	const char * _src = (const char *)src;

	//拷贝num个字节
	while (num)
	{
    
    
		*_dst = *_src;
		_dst++;
		_src++;
		num--;
	}

	return dst;


}

Esta función no puede lidiar con la superposición de memoria, como se muestra a continuación

int main()
{
    
    
	//内存重叠
	char buf[16] = "abcdef";
	my_memcpy(buf + 1, buf, strlen(buf)+1);
	printf("%s\n", buf);
	system("pause");
	return 0;
}

Como resultado,
Inserte la descripción de la imagen aquí
todo a está en la copia porque al copiar de izquierda a derecha, el carácter de la izquierda se sobrescribirá con a cada vez.
Inserte la descripción de la imagen aquí

3. Simulación para lograr memmove

Inserte la descripción de la imagen aquí
Las cuatro situaciones anteriores ocurrirán cuando la memoria se superpone:
1. La posición inicial de dst está a la izquierda de la posición inicial de src, y las dos piezas de memoria tienen el mismo tamaño . Al copiar de izquierda a derecha, el carácter anterior de src se copiará al carácter dst cada vez, por lo que no se sobrescribirá con el mismo carácter.
2. La posición inicial de dst está a la izquierda de la posición inicial de src, y el bloque de memoria de dst es más grande que el bloque de memoria de src. Al copiar de izquierda a derecha, el carácter anterior de src se copiará al dst cada vez, por lo que no lo sobrescribirá el mismo carácter.
3. La posición inicial de src dst en la posición inicial derecha, y dst es mayor o igual que el bloque de memoria src del bloque de memoria , al copiar de izquierda a derecha, el primer carácter de un src repetido cubre todos los caracteres de dst, en Al final, aparece una situación de todo a. ¡Así que esta situación debe copiarse de derecha a izquierda!
4. Si el bloque de memoria dst es más pequeño que el bloque de memoria src, esto no sucederá porque la memoria de destino es más pequeña que la memoria copiada y se produce un desbordamiento.
para resumir:

  • 1,2 se puede considerar como una situación, porque copiar de izquierda a derecha no causará problemas
  • 3 puede considerarse como una situación

Idea de realización:
Inserte la descripción de la imagen aquí
asumiendo que la izquierda es la dirección baja y la derecha es la dirección alta, entonces el caso 3 se puede expresar así

  • dst> src && src + len (src)
    • dst> src, que indica que la posición inicial de dst está a la derecha de la posición inicial de src
    • dst <src + len (src), lo que significa que la posición inicial de dst es menor que la posición final de src
    • && En los dos casos, el AND lógico indica que la posición inicial de dst debe estar en el medio de la posición inicial y la posición final de src . En pocas palabras, ¡hay una intersección entre dst y src! ! ! . Cuando se utiliza la función de operación de memoria, el espacio de dst debe ser mayor o igual que el espacio de src, así que no se preocupe si todo el espacio de dst cae en el espacio de src, es decir, la situación en la figura siguiente no aparecerá!
      Inserte la descripción de la imagen aquí
      Código
//2.模拟实现memmove
void *my_memmove(void *dst, const void *src, size_t num)
{
    
    
	//判断指针合法性
	assert(dst != NULL);
	assert(src != NULL);

	//将void *强制类型转为char *,方便按字节拷贝
	char *_dst = (char *)dst;
	const char * _src = (const char *)src;

	//情况3从右向左拷贝
	if (_dst > _src && _dst < _src + num)
	{
    
    
		//首先让dst与src指向最右边
		_dst = _dst + num - 1;
		_src = _src + num - 1;

		//拷贝num个字节
		while (num)
		{
    
    
			*_dst = *_src;
			_dst--;
			_src--;
			num--;
		}
	}
	//其他情况全部从左向右拷贝
	else
	{
    
    
		//拷贝num个字节
		while (num)
		{
    
    
			*_dst = *_src;
			_dst++;
			_src++;
			num--;
		}
	}

	return dst;
}

Verificar la superposición de la memoria

int main()
{
    
    
	//内存重叠
	char buf[16] = "abcdef";
	my_memmove(buf + 1, buf, strlen(buf) + 1);
	printf("%s\n", buf);
	system("pause");
	return 0;
}

El resultado es una
Inserte la descripción de la imagen aquí
respuesta perfecta

4. Practique la prueba si hay una diferencia en la función de operación de memoria en la función de biblioteca

El blogger usa el sistema operativo win10 de 64 bits y VS2015 ha
Inserte la descripción de la imagen aquí
pasado la verificación de laboratorio. Como se muestra en la figura anterior, no hay diferencia entre las funciones de biblioteca memcpy y memmove de la versión vs2015. La razón puede ser que la función memcpy se ha optimizado y no habrá ningún error de superposición de memoria.

Supongo que te gusta

Origin blog.csdn.net/qq_40076022/article/details/110497156
Recomendado
Clasificación