sirve - es memset() más eficiente que para bucle en C?
memset linux (6)
Es más eficiente que el bucle. así que si tengo
char x[500];
memset(x,0,sizeof(x));
o
char x[500];
for(int i = 0 ; i < 500 ; i ++) x[i] = 0;
¿Cuál es más eficiente y por qué? ¿Hay alguna instrucción especial en hardware para hacer la inicialización a nivel de bloque?
Bueno, ¿por qué no echamos un vistazo al código de ensamblaje generado, la optimización completa en VS 2010?
char x[500];
char y[500];
int i;
memset(x, 0, sizeof(x) );
003A1014 push 1F4h
003A1019 lea eax,[ebp-1F8h]
003A101F push 0
003A1021 push eax
003A1022 call memset (3A1844h)
Y tu bucle ...
char x[500];
char y[500];
int i;
for( i = 0; i < 500; ++i )
{
x[i] = 0;
00E81014 push 1F4h
00E81019 lea eax,[ebp-1F8h]
00E8101F push 0
00E81021 push eax
00E81022 call memset (0E81844h)
/* note that this is *replacing* the loop,
not being called once for each iteration. */
}
Entonces, bajo este compilador, el código generado es exactamente el mismo. memset
es rápido, y el compilador es lo suficientemente inteligente como para saber que estás haciendo lo mismo que llamar a memset
una vez, por lo que lo hace por ti.
Si el compilador realmente dejó el bucle tal como está, es probable que sea más lento, ya que puede establecer más de un bloque de tamaño de byte a la vez (es decir, podría desenrollar su bucle un poco como mínimo. Puede suponer que memset
será al menos tan rápido como una implementación ingenua como el bucle. Pruébelo en una compilación de depuración y notará que el bucle no se reemplaza.
Dicho esto, depende de lo que el compilador haga por ti. Mirar el desmontaje es siempre una buena manera de saber exactamente qué está sucediendo.
De acuerdo con lo anterior. Depende. Pero, seguro que memset es más rápido o igual que el bucle for. Si no está seguro de su entorno o es demasiado perezoso para realizar la prueba, tome la ruta segura y vaya con memset.
La respuesta es, depende''. memset
PUEDE ser más eficiente, o puede usar internamente un bucle for. No puedo pensar en un caso en el que memset
sea menos eficiente. En este caso, puede convertirse en un bucle for más eficiente: su bucle itera 500 veces estableciendo un valor de bytes de la matriz en 0 cada vez. En una máquina de 64 bits, puede realizar un bucle, estableciendo 8 bytes (un largo largo) a la vez, lo que sería casi 8 veces más rápido, y tratar los 4 bytes restantes (500% 8) al final.
EDITAR:
de hecho, esto es lo que hace memset
en glibc:
http://repo.or.cz/w/glibc.git/blob/HEAD:/string/memset.c
Como señaló Michael, en ciertos casos (donde se conoce la longitud de la matriz en tiempo de compilación), el compilador de C puede memset
línea, memset
la sobrecarga de la llamada a la función. Glibc también tiene versiones de memset
optimizadas para memset
para la mayoría de las plataformas principales, como amd64:
http://repo.or.cz/w/glibc.git/blob/HEAD:/sysdeps/x86_64/memset.S
Los buenos compiladores reconocerán el bucle for y lo reemplazarán con una secuencia en línea óptima o con una llamada a memset. También reemplazarán a memset con una secuencia en línea óptima cuando el tamaño del búfer sea pequeño.
En la práctica, con un compilador de optimización, el código generado (y, por lo tanto, el rendimiento) será idéntico.
Realmente depende del compilador y la biblioteca. Para compiladores más antiguos o compiladores simples, memset puede implementarse en una biblioteca y no funcionaría mejor que un bucle personalizado.
Para casi todos los compiladores que vale la pena usar, memset es una función intrínseca y el compilador generará código en línea optimizado para ello.
Otros han sugerido perfilar y comparar, pero no me molestaría. Sólo tiene que utilizar memset. El código es simple y fácil de entender. No se preocupe por eso hasta que sus puntos de referencia le indiquen que esta parte del código es un hotspot de rendimiento.
Sin duda, memset
será mucho más rápido que ese bucle. Observe cómo trata un carácter a la vez, pero esas funciones están tan optimizadas que configuran varios bytes a la vez, incluso utilizando, cuando estén disponibles, las instrucciones MMX y SSE.
Creo que el ejemplo paradigmático de estas optimizaciones, que generalmente pasan desapercibidas, es la función strlen
biblioteca C de GNU. Uno pensaría que tiene al menos O (n) rendimiento, pero en realidad tiene O (n / 4) u O (n / 8) dependiendo de la arquitectura (sí, lo sé, en gran O () será el mismo , pero en realidad obtienes un octavo del tiempo). ¿Cómo? strlen , pero muy bien: strlen .