2020/11/13 Conocimiento profundo de memcpy_s y funciones de memcpy

función memcpy

原型 : extern void * memcpy (void * dest, const void * src, size_t n); 这是一个函数指针 接收的是一个地址 dest是接收地址的首地址,src是源首地址,count是接收目标的大小单位为字节 位于cstring或memcpy.h头文件中。

Implementación del código fuente de memcpy en Linux

void *memcpy(void *to, const void *from, size_t n)
{
    
    
    void *xto = to;
    size_t temp, temp1;
 
    if (!n)
        return xto;
    if ((long)to & 1) {
    
    
        char *cto = to;
        const char *cfrom = from;
        *cto++ = *cfrom++;
        to = cto;
        from = cfrom;
        n--;
    }
    if (n > 2 && (long)to & 2) {
    
    
        short *sto = to;
        const short *sfrom = from;
        *sto++ = *sfrom++;
        to = sto;
        from = sfrom;
        n -= 2;
    }
    temp = n >> 2;
    if (temp) {
    
    
        long *lto = to;
        const long *lfrom = from;
#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
        for (; temp; temp--)
            *lto++ = *lfrom++;
#else
        asm volatile (
            "    movel %2,%3\n"
            "    andw  #7,%3\n"
            "    lsrl  #3,%2\n"
            "    negw  %3\n"
            "    jmp   %%pc@(1f,%3:w:2)\n"
            "4:    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "    movel %0@+,%1@+\n"
            "1:    dbra  %2,4b\n"
            "    clrw  %2\n"
            "    subql #1,%2\n"
            "    jpl   4b"
            : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
            : "0" (lfrom), "1" (lto), "2" (temp));
#endif
        to = lto;
        from = lfrom;
    }
    if (n & 2) {
    
    
        short *sto = to;
        const short *sfrom = from;
        *sto++ = *sfrom++;
        to = sto;
        from = sfrom;
    }
    if (n & 1) {
    
    
        char *cto = to;
        const char *cfrom = from;
        *cto = *cfrom;
    }
    return xto;
}

Implementación bajo ventanas

void* __cdecl memcpy(void* dst,const void* src,size_t count)
{
    
    
    void*ret=dst;
{
    
    
     extern void RtlMoveMemory(void *,const void *,size_t count);
     RtlMoveMemory(dst,src,count);
}
while(count--){
    
    
    *(char *)dst = *(char *)src;
    dst = (char *)dst+1;
    src = (char *)src+1;
}
return (ret);
} 
//改进之后的memcpy

   void *my_memcpy_byte(void *dst, const void *src, int n)
{
    
    
  if (dst == NULL || src == NULL || n <= 0)
      return NULL;

  char * pdst = (char *)dst;
  char * psrc = (char *)src;

  if (pdst > psrc && pdst < psrc + n)
  {
    
    
      pdst = pdst + n - 1;
      psrc = psrc + n - 1;
      while (n--)
          *pdst-- = *psrc--;
  }
  else
  {
    
    
      while (n--)
          *pdst++ = *psrc++;
  }
  return dst;
}

Precauciones de uso

  • ¿Está vacía la dirección src?
  • Si las direcciones src y dest se superponen, ¿se superponen de forma segura o se superponen parcialmente?
  • Puede haber ineficiencias al tratar con grandes bloques de datos.

función memcpy_s

函数 memcpy_s (void * dest, size_t numberOfElements, const void * src, size_t count)

Prototipo de función

errno_t memcpy_s(
   void *dest,
   size_t numberOfElements,
   const void *src,
   size_t count 
);

dest: la dirección del destino
numberOfElements: el tamaño del destino
src: la dirección de origen
recuento: el número de bytes a copiar
Primero solicite un tamaño de búfer, número de elementos, cuando el recuento exceda este búfer, se desbordará

memcpy_s detallado

El primer parámetro es la dirección de la memoria de destino, el segundo parámetro es el tamaño del búfer de la memoria de destino, el tercer parámetro es la dirección de la memoria de origen y el cuarto es el tamaño del búfer de la memoria de origen. El valor de retorno es un código de error.
¿Por qué este valor de retorno es un código de error? Porque esta versión agrega detección básica de errores. Si el tamaño del búfer de origen es 0, es decir, el recuento es 0, la función devuelve 0 y no hace nada. Esta función no comprueba si el puntero de destino es NULO, por lo que debe prestar atención a la comprobación usted mismo. Si el puntero tiene un valor, pero es un valor no válido, la función no puede verificar si es una memoria válida, pero recopilará esta información y proporcionará la información necesaria para la depuración cuando el programa falle.
Luego, verifique si la dirección de origen está vacía o si el recuento es mayor que sizeInBytes. Se cumple una de las dos condiciones. La función primero borra la memoria de destino a 0 llamando a la función memset con el tamaño especificado por sizeInBytes. Se puede ver aquí que si el tamaño pasado por sizeInBytes excede el objetivo El tamaño del búfer también trae peligros ocultos Una vez que se borra la memoria de otros procesos u otros subprocesos, causará problemas y también puede causar violaciones de funcionamiento de la memoria. Por lo tanto, el tamaño del segundo parámetro no puede exceder el tamaño del búfer de destino, en bytes. Luego, el programa recopila información de error y finalmente devuelve un código de error y no ejecuta el proceso de copia de la memoria. Como se mencionó anteriormente, la entrada en cualquiera de las dos condiciones conducirá a una falla, por lo que al recopilar información, el programa juzgará las condiciones de entrada y luego la recopilará.
Solo cuando estas comprobaciones pasen, se llamará a la función memcpy para ejecutar el proceso de copia de memoria. El segundo parámetro solo se usa internamente para detectar y borrar la memoria de destino.
La función memcpy_s devuelve 0 después de la ejecución, por lo que comprobar si el valor devuelto es 0 no puede determinar si tiene éxito. Pero el valor de retorno no es cero, eso significa falla.
Aunque se dice que la función con la versión _s es una versión segura, habrá problemas. Preste atención al usarla. Incluso si no falla a veces, una vez que se reescribe la memoria de otros subprocesos, inevitablemente causará el programa se ejecute de manera anormal, porque los datos del hilo se destruyen, al menos la lógica saldrá mal.
Sin embargo, la función de la versión _s proporciona una cierta detección y también puede informar errores en la versión de lanzamiento, lo que puede depurar aún más el problema, mientras que memcpy no informará errores en la versión de lanzamiento.

Este artículo hace referencia: análisis de funciones Memcpy y Memcpy_s de C ++

Supongo que te gusta

Origin blog.csdn.net/weixin_43624728/article/details/109677836
Recomendado
Clasificación