UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Se describen las rutinas que manipulan strings, cuyos prototipos se encuentran en string.h #include <string.h> typedef unsigned size_t; #define NULL 0 /* define tipo requerido por sizeof */ /* terminador nulo */ Definición de string. La siguiente definición reserva espacio para un string como un arreglo de caracteres. La definición de un string como arreglo de caracteres, debe incluir un espacio para el carácter fin de string (el carácter NULL). Quizás es mejor definir el terminador de string como null, para evitar confusiones con el valor de un puntero nulo. char string[6]; /*crea string con espacio para 6 caracteres. Indice varía entre 0 y 5 */ string[5] = NULL; string \0 El nombre del string es un puntero constante que apunta al primer carácter del string. Por ser constante no se le puede asignar nuevos valores o modificar. La definición de un string como un puntero a carácter, puede ser inicializada asignándole una constante de tipo string. La que se define como una secuencia de cero o más caracteres entre comillas dobles; el compilador agrega el carácter ‘\0’ automáticamente al final. Si dentro del string se desea emplear la comilla doble debe precedérsela por un \. En caso de escribir, en el texto de un programa, un string de varias líneas, la secuencia de un \ y el retorno de carro(que es invisible en la pantalla) no se consideran parte del string. char * str1 = "abcdefghi"; /* tiene 10 caracteres, incluido el NULL que termina el string.*/ Un argumento de tipo puntero a carácter puede ser reemplazado en una lista de parámetros, en la definición de una función por un arreglo de caracteres sin especificar el tamaño. En el caso del ejemplo anterior: char str1[ ]. La elección entre estas alternativas suele realizarse según sea el tratamiento que se realice dentro de la función; es decir, si las expresiones se elaboran en base a punteros o si se emplea manipulación de arreglos. Prof. Leopoldo Silva Bijit. 18-08-2003 15 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Copia el string fuente en el string destino. Se detiene la copia después de haber copiado el carácter nulo del fin del string. Retorna la dirección del string destino. char *strcpy(char * destino, register const char * fuente) { register char * cp= destino; while(*cp++ = *fuente++) continue; return destino; } destino cp fuente El diagrama ilustra los punteros fuente y cp, después de haberse realizado la copia del primer carácter. Se muestra el movimiento de copia y el de los punteros. Cuando el contenido de *fuente es el carácter NULL, primero lo copia y la expresión resultante de la asignación toma valor cero, que tiene valor falso para la condición, terminando el lazo while. La instrucción continue puede aparecer en el bloque de acciones de un while, do o for. Su ejecución lleva a reevaluar la condición de continuación del bloque de repetición más interno (en caso de bloques anidados). En el caso de la función anterior podría haberse omitido la instrucción continue; ya que un punto y coma se considera una acción nula. El operador de postincremento opera sobre un left value(que recuerda un valor que puede colocarse a la izquierda de una asignación). Un lvalue es un identificador o expresión que está relacionado con un objeto que puede ser accesado y cambiado en la memoria. El uso de estos operadores en expresiones produce un efecto lateral, en el sentido que se efectúan dos acciones. Primero se usa el valor del objeto en la expresión y luego éste es incrementado en uno. El operador de indirección ( el *) y el operador ++ tienen la misma precedencia, entonces se resuelve cuál operador recibe primero el operando mediante su asociatividad, que en el caso de los operadores unarios es de derecha a izquierda. Es decir *fuente++ se interpreta según: ( * (fuente++) ) . La expresión toma el valor del puntero fuente y lo indirecciona, posteriormente incrementa en uno al puntero. En la expresión (* fuente) ++, mediante el uso de paréntesis se cambia la asociatividad, la expresión toma el valor del objeto apuntado por fuente, y luego incrementa en uno el valor del objeto, no del puntero. Prof. Leopoldo Silva Bijit. 18-08-2003 16 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Puede evitarse la acción doble relacionada con los operadores de pre y postincremento, usando éstos en expresiones que sólo contengan dichos operadores. En el caso de la acción de repetición: while(*cp++ = *fuente++) continue; Puede codificarse: while( *cp = *fuente) {cp++, fuente++}; Sin embargo los programadores no suelen emplear esta forma. Adicionalmente no producen igual resultado, ya que en la primera forma los punteros quedan apuntando una posición más allá de los caracteres de fin de string; la segunda forma deja los punteros apuntando a los terminadores de los strings. Ambas formas satisfacen los requerimientos de srtcpy. La primera forma sólo tendría ventajas si el procesador tiene mecanismos de direccionamientos autoincrementados, y si el compilador emplea dichos mecanismos al compilar la primera forma. Cuando en la lista de parámetros de una función aparece la palabra reservada const precediendo a una variable de tipo puntero, el compilador advierte un error si la función modifica la variable a la que el puntero apunta. No se valida si el espacio a continuación de destino puede almacenar el string fuente sin sobreescribir en el espacio asignado a otras variables. Ejemplo: #include <string.h> #include <stdio.h> char string[10]; /*crea string con espacio para 10 caracteres */ char * str1 = "abcdefghi"; /* tiene 10 caracteres, incluido el NULL que termina el string.*/ int main(void) { strcpy(string, str1); printf("%s\n", string); return 0; } strncpy copia n caracteres desde el string fuente hacia el string destino. Si el string fuente tiene menos de n caracteres rellena con nulos hasta completar la copia de n caracteres. Si el string fuente tiene n o más caracteres el string destino no queda terminado en un nulo. char *strncpy(register char * destino, register const char * fuente, register size_t n ) { register char * cp = destino; while( n ) { n--; if(!(*cp++ = *fuente++)) break; } while( n--) *cp++ = 0; return destino; } Prof. Leopoldo Silva Bijit. 18-08-2003 17 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C La sentencia break termina el bloque de repetición (más interno, si existen estructuras repetitivas anidadas), y pasa a ejecutar la instrucción siguiente al bloque. Si se copia el fin del string fuente se activa el break y comienza el segundo while que produce el relleno de nulos. Si se copian n caracteres en el primer while, el segundo no se efectúa, ya que se entra a éste con un valor cero de n. Concatena una copia del string fuente luego del último carácter del string destino. El largo del string resultante es la suma: strlen(dest) + strlen(src). Retorna un puntero al string destino, que ahora contiene la concatenación. char *strcat(register char * destino, register const char * fuente) { register char *cp= destino; while(*cp) cp++; while(*cp++ = *fuente++) continue; /* return destino; } El primer while deja el puntero cp apuntando al carácter de fin del string destino. Luego el segundo while efectúa la copia, sobreescribiendo el NULL del string destino, con el primer carácter del string fuente. La función también concatena un string fuente nulo. destino Ejemplo: #include <string.h> #include <stdio.h> char destino[25]; char *espacio = " ", *fin = "Final", *destino = "Inicio"; int main(void) { strcat(destino, espacio); strcat(destino, fin); printf("%s\n", destino); return 0; } cp fuente strncat concatena al final del string destino a lo más n caracteres del string fuente. char *strncat(register char * destino, register const char * fuente, register size_t n ) { register char * cp = destino; while(*cp) cp++; /*apunta al final del string destino */ while( n && (*cp++ = *fuente++) ) n--; if( n == 0) *cp = 0; return destino; } Prof. Leopoldo Silva Bijit. 18-08-2003 18 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Si fuente tiene menos de n caracteres, el segundo operador del and copia el fin de string. Si el string fuente tiene n o más caracteres, es el primer operando del and es el que da por terminado el segundo while; saliendo de éste con un valor cero de n. Es para este último caso que está el if final que escribe el terminador del string destino. El máximo largo del string destino resultante es strlen(destino al inicio) + n. Agrega una porción del string fuente a continuación del string destino. Largo de un string. Retorna el número de caracteres del string s. No cuenta el carácter de terminación. size_t strlen(const char * s) { register const char * cp= s; while(*cp++) continue; return (cp-1) - s; } El while termina cuando *cp tiene valor cero. Pero debido al operador de postincremento, al salir del while, cp queda apuntado una posición más allá de la posición que ocupa el NULL. Entonces cp-1, apunta al NULL. Y la resta de punteros, produce un entero como resultado; éste da el número de caracteres del string. Si a s se le suman 5, se tiene el valor del puntero que apunta al terminador del string, en el caso del ejemplo que se ilustra a continuación; entonces (cp-1) – s resulta 5 en este caso. s \0 cp Compara dos strings. La comparación comienza con el primer carácter de cada string y continua con los caracteres subsecuentes hasta que los caracteres correspondientes difieren o hasta que se llegue al final de uno de los strings. int strcmp(register const char * s1, register const char * s2) { register signed char r; while( !( r = *s1 - *s2++) && *s1++) continue; return r; } Prof. Leopoldo Silva Bijit. 18-08-2003 19 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Retorna un valor entero: Menor que cero si s1 < s2 Igual a cero si s1 == s2 Mayor que cero si s1 > s2 Si los caracteres *s1 y *s2 son iguales, r es cero; y el valor lógico del primer operando del and es verdadero. Si son diferentes, termina el lazo de repetición. Si el valor de *s2 es mayor que el valor de *s1, r será negativo; implicando que el string s2 es "mayor" que el string s1. Si *s2 es el carácter NULL, r será positivo si *s1 no es cero, terminando el while; implicando que s1 > s2. Si *s1 es el carácter NULL, r será negativo si *s2 no es cero, terminando el while; implicando que s1 < s2. Strncmp compara hasta n caracteres de los strings s1 y s2. La comparación comienza con el primer carácter de cada string y continua con los caracteres siguientes hasta que éstos difieran o hasta que se hayan revisado n. int strncmp(register const char * s1, register const char * s2, size_t n) { while( n--) { if(*s1 == 0 || *s1 != *s2) return (*s1 - *s2); s1++; s2++; } return 0; } Para los primeros n caracteres, si los caracteres difieren o se llegó al fin del string s1 se retorna la resta del valor entero asociado a los caracteres. Si s2 es más corto que s1, los caracteres difieren ya que *s2 es cero, y el retorno será positivo; indicando s1 > s2. Strstr encuentra la primera ocurrencia de un substring s2 en un string s1. Si encuentra s2 en s1, retorna un puntero al carácter de s1 en que se inicia el substring que es igual a s2; si no lo encuentra retorna un puntero nulo. char *strstr(register const char * s1, register const char * s2) { while(s1 && *s1) { if(strncmp(s1, s2, strlen(s2)) == 0) return (char *)s1; s1 =strchr(s1+1, *s2); } return (char *) 0; } La condición del if es verdadera si s2 está contenido en s1, con retorno exitoso. Si no lo encuentra busca el primer carácter de s2(mediante strchr) a partir del siguiente carácter de s1; si lo encuentra avanza s1 hasta esa coincidencia; si no lo encuentra s1 será un puntero Prof. Leopoldo Silva Bijit. 18-08-2003 20 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C nulo, dando término al while(ya que el primer operando del and será falso). También termina el while si s1 es un string nulo. Busca la primera ocurrencia de un carácter c en el string s. Si lo encuentra retorna un puntero al carácter c; en caso contrario, si c no está presente en s, retorna un puntero nulo. char *strchr(register const char * s, int c) { while( *s ) { if( *s == (char) c ) return (char *) s; s++;} return (char *) 0; } El tipo char es tratado como entero con signo de 8 bits(-128 a +127) y es promovido automáticamente a tipo entero. Sin embargo se emplea un conversión explícita de entero a char mediante el molde o cast: (char) c Debido a que el parámetro formal se trata como puntero a una constante string(para evitar que la función modifique a s), se debe efectuar una conversión del tipo de puntero para el retorno, se pasa a puntero a carácter (char *) el puntero a string constante: const char *. La búsqueda de c en s es hacia delante (de izquierda a derecha, o de arriba hacia abajo). Si s apunta al terminador del string, la expresión *s tiene valor cero, y la condición del while es falsa, por lo tanto no busca el terminador del string. El fin de string(terminador nulo) es parte del string. Si se desea que la búsqueda strchr(s, 0) retorne un puntero al terminador nulo del string s, debe efectuarse la siguiente modificación: char *strchr(register const char * s, int c) { while( *s ) { if( *s == (char) c ) return (char *) s; s++;} if( *s == (char) c ) return (char *) s; return (char *) 0; } La rutina modificada puede buscar el terminador del string incluso en un string nulo. strrchr encuentra la última ocurrencia del carácter c en el string s. Si encuentra c en s, retorna un puntero al carácter encontrado; en caso contrario, un puntero nulo. La búsqueda la efectúa en reversa. cp char *strrchr(register const char * s, int c) { register const char * cp = s; while(*s) s++; /* s queda apuntado al terminador */ while(s != cp) { s--; if(*s == (char)c ) return (char *)s;} return (char *) 0; } Prof. Leopoldo Silva Bijit. 18-08-2003 \0 s 21 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C El diagrama ilustra los punteros una vez terminado el primer while. El terminador nulo es considerado parte del string. Si se desea buscar el terminador del string debe modificarse la rutina anterior, o utilizar strchar. strpbrk busca en el string s1 la primera ocurrencia de cualquier carácter presente en s2; retorna un puntero al primer encontrado, en caso que ningún carácter de s2 esté presente en s1 retorna un puntero nulo. char *strpbrk(register const char * s1, register const char * s2) { while(*s1) { if(strchr(s2, *s1)) return (char *)s1; s1++; } return (char *)0; } strcspn encuentra el segmento inicial del string s1 que no contiene caracteres que se encuentren presentes en s2. Retorna el largo del segmento encontrado. size_t strcspn(register const char * s1, register const char * s2) { register size_t i=0; while(*s1 && !strchr(s2, *s1) ) {s1++; i++;} return i; } A partir del primer carácter de s1 se revisa que éste no esté presente entre los caracteres que forman s2. strspn encuentra el segmento inicial del string s1 que solamente contiene caracteres que se encuentren presentes en s2. Retorna el largo del segmento encontrado. size_t strspn(register const char * s1, register const char * s2) { register size_t i = 0; while(*s1 && strchr(s2, *s1) ) { s1++; i++;} return i; } Se mantiene realizando el bloque mientras encuentre los caracteres de s1 en s2 y no sea fin de string s1. Strtok busca el primer substring de s1 que está antes del string s2 que se considera un separador. Se considera que s1 es un string formado por una secuencia de cero o más símbolos(tokens) separados por el string s2. Prof. Leopoldo Silva Bijit. 18-08-2003 22 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C La función strtkn permite obtener todos los tokens mediante llamados subsiguientes primero. Para esto el primer llamado debe retornar un puntero al primer token, y escribir carácter NULL en el string s1, inmediatamente después del último carácter del token que retorna. Los siguientes llamados deben realizarse con un puntero nulo en el primer argumento. separador s2 puede ser diferente para cada una de las siguientes invocaciones. Si no encuentran símbolos la función debe retornar un puntero nulo. al un se El se Como es una rutina que puede llamarse varias veces, su diseño debe incluir una variable estática que permanezca entre llamados. Ya que los argumentos y variables locales sólo existen mientras la función esté activa, debido a que se mantienen en un frame en el stack. s1 t1 s2 t2 s2 t2 s2 sp El primer llamado a strtrk, debe retornar s1, colocando un nulo en el primer carácter de s2, y fijar la posición de la estática sp inmediatamente después del terminador recién insertado. Los llamados subsiguientes llevan un NULL en el primer argumento, correspondiente al puntero al string s1; esto le indica a la función que debe emplear ahora sp para seguir buscando tokens. El primer if, si s1 es un puntero nulo, fija s1 en el valor guardado en la estática sp por la invocación anterior. Si el primer llamado se efectúa sobre un string nulo, debe estar inicializada la estática sp. El segundo if, retorna un puntero nulo, si el llamado inicial es con un puntero nulo, o si se agotó la búsqueda de símbolos en llamados subsiguientes (encuentra sp con valor nulo). char *strtok(register char * s1, register const char * s2) { static char * sp = NULL; if(!s1) s1 = sp; if(!s1) return NULL; s1 += strspn(s1, s2); /* salta separador */ if(!*s1) return sp = NULL; sp = s1 + strcspn(s1, s2); if(*sp) *sp++ = '\0'; else sp = NULL; return s1; /* puntero al token encontrado */ } Mediante la función strspn se saltan los caracteres pertenecientes al separador s2, y s1 queda apuntado al primer carácter siguiente al separador s2. El tercer if, si se llegó al final del string, fija sp en puntero nulo, y retorna un puntero nulo. No se efectúa la acción del tercer if, si quedan caracteres por escanear. Prof. Leopoldo Silva Bijit. 18-08-2003 23 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Mediante la función strcspn se fija sp una posición más allá del último carácter del encontrado. El cuarto if, fija sp en puntero nulo, si se agotó la búsqueda (se efectúa el else); en contrario si quedan caracteres por escanear, coloca un carácter nulo para finalizar el encontrado, y avanza sp una posición más adelante. El tipo del argumento de s1 no puede ser un puntero constante, ya que se escribe string. token caso, token en el Si por ejemplo el string s1 tiene el valor "abc, dd,efg" y si el separador s2 es el string ","; se encuentra, después del primer llamado el token: abc. Luego del segundo(con primer argumento NULL) el token: dd. Finalmente el símbolo: efg. strdup crea un duplicado del string s, obteniendo el espacio con un llamado a malloc. El espacio requerido es de (strlen(s) + 1) bytes, para incluir el terminador, el que es insertado por strcpy. Si malloc no puede asignar espacio retorna puntero nulo. La función retorna un puntero al duplicado; en caso que falle malloc retorna un puntero nulo. El programador es responsable de liberar el espacio ocupado cuando ya no sea necesario, empleando la función free. char *strdup(register const char * s) { register char * cp; if(cp = (char *) malloc(strlen(s)+1)) strcpy(cp, s); return cp; } Con las siguientes definiciones: char *duplicado; char *string = "1234"; Un ejemplo de uso es: duplicado = strdup(string); Y para liberar el espacio: free(duplicado); El prototipo de malloc es: void *malloc(size_t size); Malloc retorna un puntero de tipo void o un puntero genérico. Se emplean cuando el compilador no puede determinar el tamaño del objeto al cual el puntero apunta. Por esta razón los punteros de tipo void deben ser desreferenciados mediante casting explícito. El siguiente ejemplo muestra que a un puntero tipo void se le puede asignar la dirección de un entero o un real. Pero al indireccionar debe convertirse el tipo void al del objeto que éste apunta. int x; Prof. Leopoldo Silva Bijit. 18-08-2003 24 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C float r; void *p; p = &x; * (int *) p = 2; p = &r; *(float *)p = 1.1; El conjunto de funciones cuyos prototipos se encuentran en string.h también incluye un grupo de funciones que manipulan bloques de memoria. Los bloques son referenciados por punteros de tipo void, en la lista de argumentos. Luego en las funciones se definen como variables locales punteros a caracteres, que son iniciados con los valores de los punteros genéricos amoldados a punteros a caracter. memcpy Copia un bloque de n bytes desde la dirección fuente hacia la dirección destino. void *memcpy(void * destino, const void * fuente, register size_t n) { register char *d = (char *)destino; register const char *s= (char *)fuente; while(n--) *d++ = *s++; return destino; } Si fuente y destino se traslapan la conducta de memcpy es indefinida. Ya que no se puede sobreescribir el bloque fuente, que se trata como puntero genérico constante. Dentro de la función se emplean punteros locales a caracteres. Copia no más de n bytes desde el bloque apuntado por fuente hacie el bloque apuntado por destino, deteniéndose cuando copia el carácter c. Retorna un puntero al bloque destino, apuntando al byte siguiente donde se copió c. Retorna NULL si no encuentra a c en los primeros n bytes del bloque fuente. void *memccpy (void *destino, const void *fuente, int c, size_t n) { register const char *s = (char *)fuente; register char *d = (char *)destino; register const char x = c; register size_t i = n; while (i-- > 0) if ((*d++ = *s++) == x) return d; return NULL; } Se emplean locales de tipo registro para acelerar la copia. Nótese que los punteros de tipo void de los argumentos son los valores iniciales de los registros con punteros a caracteres. Prof. Leopoldo Silva Bijit. 18-08-2003 25 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Con memmove, si los bloques apuntados por fuente y destino se traslapan, los bytes ubicados en la zona de traslapo se copian correctamente. void *memmove(void * destino, void * fuente, register size_t n) { register char *d= (char *)destino; register char *s = (char *)fuente; if(s < d && s+n >=d) { s += n; d += n; do *--d = *--s; while(--n); } else if(n) do *d++ = *s++; while(--n); return destino; } La condición de traslapo del bloque s sobre el bloque d, se ilustra en el diagrama de más a la derecha. En este caso se efectúa la copia en reversa. Se sobreescriben los últimos elementos del bloque apuntado por s; es decir los que primero fueron copiados. La negación lógica de la condición de traslapo, por De Morgan, es: (s>=d || s+n<d ) Los dos casos del or se ilustran en las dos figuras de más a la izquierda. En el caso que ilustra la figura central, no hay traslapo. En el caso s>=d, si d+n>=s, se produce traslapo y se sobreescriben las primeras posiciones del bloque s, las que primero fueron copiadas (cuando se ejecuta el else, avanzado los punteros hacia direcciones cada vez mayores). d s < d && s+n >= d s + n <d s>=d s s n s d n d Debido a que el bloque fuente puede ser sobrescrito, no puede ser un puntero vacío constante. Los punteros a carácter s y d, son iniciados con los valores amoldados (cast) a punteros a carácter de fuente y destino. Prof. Leopoldo Silva Bijit. 18-08-2003 26 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C memcmp compara los primeros n bytes de los bloques s1 y s2, como unsigned chars. int memcmp(const void *s1, const void *s2, size_t n) { int i; register const unsigned char *a1, *a2; a1 = (unsigned char *)s1; a2 = (unsigned char *)s2; while(n--) if( i = (int)(*a1++ - *a2++) ) return i; return 0; } Valor de retorno menor que cero si s1 < s2 Valor de retorno igual a cero si s1 == s2 Valor de retorno mayor que cero si s1 > s2 Rellena n bytes del bloque s con el byte c. Retorna puntero genérico al bloque. void *memset(void * s, int c, register size_t n) { register char * p = (char *)s; while(n--) *p++ = (char) c; return s; } Efectuar movimientos de bloques orientados al carácter es ineficiente. Por esta razón las funciones de movimiento tratan de mover palabras. Primero se mueven los bytes parciales de una palabra, luego se pueden mover palabras alineadas; para finalmente, copiar los bytes presentes en la última palabra. Estas funciones, implementadas en base a macros para mejorar la velocidad, son dependientes del procesador. Se requiere conocer el ancho de la palabra y el ordenamiento de los bytes dentro de la palabra(little o big endian). El siguiente ejemplo introduce en un entero de 32 bits, el carácter '4' en el byte más significativo, luego el '3', después el '2', y el carácter '1' en el byte menos significativo. Luego convierte la dirección de i en un puntero a carácter, e imprime el string de largo 4. En el string el byte con la menor dirección queda más a la izquierda, y el byte con dirección mayor queda a la derecha. unsigned long int i; if (sizeof (i) == 4) { i = (((((('4' << 8) + '3') << 8) + '2') << 8) + '1'); printf ("Orden de los Bytes = %.4s\n", (char *) &i); } else printf (" \nNo es una máquina de 32 bits"); Prof. Leopoldo Silva Bijit. 18-08-2003 27 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C Los strings asociados reflejan el ordenamiento de los bytes dentro de la palabra. Suelen denominarse: LITTLE ENDIAN "1234" BIG ENDIAN "4321" PDP ENDIAN "3412" rettype memmove (a1, a2, len) a1const void *a1; a2const void *a2; size_t len; { unsigned long int dstp = (long int) dest; unsigned long int srcp = (long int) src; /* This test makes the forward copying code be used whenever possible. Reduces the working set. */ if (dstp - srcp >= len) /* *Unsigned* compare! */ { /* Copy from the beginning to the end. */ /* If there not too few bytes to copy, use word copy. */ if (len >= OP_T_THRES) { /* Copy just a few bytes to make DSTP aligned. */ len -= (-dstp) % OPSIZ; BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); /* Copy whole pages from SRCP to DSTP by virtual address manipulation, as much as possible. */ PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); /* Copy from SRCP to DSTP taking advantage of the known alignment of DSTP. Number of bytes remaining is put in the third argument, i.e. in LEN. This number may vary from machine to machine. */ WORD_COPY_FWD (dstp, srcp, len, len); /* Fall out and copy the tail. */ } /* There are just a few bytes to copy. Use byte memory operations. */ Prof. Leopoldo Silva Bijit. 18-08-2003 28 UNIVERSIDAD TECNICA FEDERICO SANTA MARIA DEPARTAMENTO DE ELECTRONICA Programación Avanzada en C BYTE_COPY_FWD (dstp, srcp, len); } else { /* Copy from the end to the beginning. */ srcp += len; dstp += len; /* If there not too few bytes to copy, use word copy. */ if (len >= OP_T_THRES) { /* Copy just a few bytes to make DSTP aligned. */ len -= dstp % OPSIZ; BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ); /* Copy from SRCP to DSTP taking advantage of the known alignment of DSTP. Number of bytes remaining is put in the third argument, i.e. in LEN. This number may vary from machine to machine. */ WORD_COPY_BWD (dstp, srcp, len, len); /* Fall out and copy the tail. */ } /* There are just a few bytes to copy. Use byte memory operations. */ BYTE_COPY_BWD (dstp, srcp, len); } RETURN (dest); } Prof. Leopoldo Silva Bijit. 18-08-2003 29