
Angus
00018 void *memcpy(void *dst, const void *src, size_t len)
00019 {
00020 size_t i;
00021
00022 /*
00023 * memcpy does not support overlapping buffers, so always do it
00024 * forwards. (Don't change this without adjusting memmove.)
00025 *
00026 * For speedy copying, optimize the common case where both pointers
00027 * and the length are word-aligned, and copy word-at-a-time instead
00028 * of byte-at-a-time. Otherwise, copy by bytes.
00029 *
00030 * The alignment logic below should be portable. We rely on
00031 * the compiler to be reasonably intelligent about optimizing
00032 * the divides and modulos out. Fortunately, it is.
00033 */
00034
00035 if ((uintptr_t)dst % sizeof(long) == 0 &&
00036 (uintptr_t)src % sizeof(long) == 0 &&
00037 len % sizeof(long) == 0) {
00038
00039 long *d = dst;
00040 const long *s = src;
00041
00042 for (i=0; i<len/sizeof(long); i++) {
00043 d[i] = s[i];
00044 }
00045 }
00046 else {
00047 char *d = dst;
00048 const char *s = src;
00049
00050 for (i=0; i<len; i++) {
00051 d[i] = s[i];
00052 }
00053 }
00054
00055 return dst;
00056 }
Estaba pasando por una implementación de memcpy
, para comprender en qué se diferencia del uso de un bucle. Pero no pude ver ninguna diferencia entre usar un bucle en lugar de memcpy
como memcpy
usa bucle de nuevo internamente para copiar.
no pude entender if
parte que hacen para números enteros – i < len/sizeof(long)
. ¿Por qué es necesario este cálculo?
No pude entender si parte lo hacen para números enteros. i < largo/tamaño de (largo). ¿Por qué es necesario este cálculo?
Porque están copiando palabras, no bytes individuales, en este caso (como dice el comentario, es una optimización: requiere menos iteraciones y la CPU puede manejar datos alineados con palabras de manera más eficiente).
len
es el número de bytes para copiar, y sizeof(long)
es el tamaño de una sola palabrapor lo que el número de elementos para copiar (es decir, iteraciones de bucle para ejecutar) es len / sizeof(long)
.
para entender en qué se diferencia del uso de un bucle. Pero no pude ver la diferencia de usar un bucle en lugar de memcpy, ya que memcpy usa loop nuevamente internamente para copiar
Bueno, entonces usa un bucle. Tal vez otras implementaciones de libc no lo hagan así. De todos modos, ¿cuál es el problema/pregunta si usa un bucle? Además, como puede ver, hace más que un ciclo: verifica la alineación y realiza un tipo diferente de ciclo dependiendo de la alineación.
No pude entender si parte lo hacen para números enteros. i < largo/tamaño de (largo). ¿Por qué es necesario este cálculo?
Esto es verificar la alineación de palabras de memoria. Si las direcciones de origen y de destino están alineadas por palabra, y la copia de longitud es múltiplo del tamaño de palabra, entonces realiza una copia alineada por palabra (long
), que es más rápido que usar bytes (char
), no solo por el tamaño, sino también porque la mayoría de las arquitecturas hacen copias alineadas con palabras mucho más rápido.

huseyin tugrul buyukisik
len%sizeof(long)
comprueba si está intentando copiar largos completos que no forman parte de long
.
00035 if ((uintptr_t)dst % sizeof(long) == 0 &&
00036 (uintptr_t)src % sizeof(long) == 0 &&
00037 len % sizeof(long) == 0) {
00038
00039 long *d = dst;
00040 const long *s = src;
00041
00042 for (i=0; i<len/sizeof(long); i++) {
00043 d[i] = s[i];
00044 }
comprueba la alineación y, si es cierto, copia rápidamente (sizeof(long)
bytes a la vez).
00046 else {
00047 char *d = dst;
00048 const char *s = src;
00049
00050 for (i=0; i<len; i++) {
00051 d[i] = s[i];
00052 }
00053 }
esto es para las matrices desalineadas (copia lenta (1 byte a la vez))
for (i=0; i<len/sizeof(long); i++) {
d[i] = s[i];
}
En este ciclo for, cada vez que un long
se copia, hay un tamaño total de len
para copiar, por eso necesita i<len/sizeof(long)
como condición para terminar el bucle.
Estaba pasando por una implementación de memcpy
, para comprender en qué se diferencia del uso de un bucle. Pero no pude ver ninguna diferencia entre usar un bucle en lugar de memcpy, ya que memcpy
usa bucle de nuevo internamente para copiar.
Loop (sentencias de control) es uno de los elementos básicos adyacentes a if (sentencias de decisión) y algunas otras cosas similares. Entonces, la pregunta aquí no es sobre cuál es la diferencia entre el bucle normal y el uso memcpy
.
memcpy
solo ayuda en su tarea brindándole una llamada API lista para usar, en lugar de tener que escribir 20 líneas de código para una cosa insignificante. Si lo desea, puede optar por escribir su propio código para proporcionarle la misma funcionalidad.
El segundo punto, como ya se señaló anteriormente, es que, el mejoramiento proporciona entre long
tipo de datos y otros tipos. Porque en long
está copiar un bloque de datos a la vez lo que llamamos una palabra en lugar de copiar byte por byte, lo que llevaría más tiempo. En caso de largo, la misma operación que requeriría 8 iteraciones para completar, memcpy
lo hace en una sola iteración copiando la palabra a la vez.

Pankaj Suryawanshi
Como si ve el código ensamblador de memcpy, muestra que en el sistema de 32 bits, cada registro es de 32 bits y puede almacenar 4 bytes a la vez, si copia solo un byte en el registro de 32 bits, la CPU necesita un ciclo de instrucción adicional.
Si len/count está alineado en el múltiplo de 4, podemos copiar 4 bytes en un ciclo
MOV FROM, R2
MOV TO, R3
MOV R2, R4
ADD LEN, R4
CP: MOV (R2+), (R3+) ; "(Rx+)" means "*Rx++" in C
CMP R2, R4
BNE CP
¿De dónde viene este código? He visto implementaciones memcpy mejor optimizadas…
– Maxime Cheramy
11 de julio de 2013 a las 11:08
@Maxime: ¿cómo lo sabría? ¡Ni siquiera conoce el procesador de destino (o el compilador para el caso)!
-Olof Forshell
11 de julio de 2013 a las 11:20
@Angus, a juzgar por su respuesta en stackoverflow.com/questions/11772553/… parece entender la alineación. los
long
es una palabra del procesador y la dirección debe estar alineada con la palabra del procesador para una copia más rápida (la mayoría de las arquitecturas hacen copias más rápidas en datos alineados). Si no puede hacerlo, hágalo lentamente, byte por byte. Hay buenas respuestas a continuación.– tontería
11 de julio de 2013 a las 11:20
¿Esta función no rompe las reglas de creación de alias (acceder a la memoria a través de un largo * que no se declaró necesariamente como largo) y, por lo tanto, es un comportamiento indefinido?
– jcodificador
11 de julio de 2013 a las 12:04
@jcoder la implementación de la implementación no tiene que seguir ninguna regla. Sería una violación si copiara este código en una función de su propio nombre y lo usara como tal.
–MM
21 de agosto de 2014 a las 19:47