¿Por qué strchr toma una int para encontrar el char?

La función strchr en la biblioteca estándar C busca un char en una cadena, pero su firma toma una int para el carácter de búsqueda. En estas dos implementaciones que encontré, la implementación arroja este int a un char :

 char *strchr(const char *s, int c) { while (*s != (char)c) if (!*s++) return 0; return (char *)s; } char *strchr(const char *s, int c) { while (*s && *s != (char)c) s++; if (*s == c) return (char *)s; return NULL; } 

¿Alguien sabe por qué? ¿Por qué no simplemente tomar un char como parámetro?

Las razones de eso son puramente históricas. Tenga en cuenta que en los viejos tiempos del lenguaje C (K y R C) no existía el prototipo de función . Una función strchr en esos tiempos se declararía como

 char *strchr(); 

y se define en estilo K & R como

 char *strchr(s, c) char *s; char c; { /* whatever */ } 

Sin embargo, en lenguaje C (en K & R C y en el moderno también) si la función se declara sin un prototipo (como se muestra arriba), los parámetros pasados ​​en cada llamada a función están sujetos a las llamadas promociones de argumento predeterminadas . En las promociones de argumento predeterminadas, cualquier tipo integral menor que int (o unsigned int ) siempre se convierte en int (o unsigned int ). Es decir, cuando los parámetros no se declaran, cada vez que pasa un valor char como argumento, este valor se convierte implícitamente en int , y en realidad pasa físicamente como un int . Lo mismo es cierto para short . (Por cierto, float se convierte en el double por las promociones argumento predeterminado). Si dentro de la función el parámetro se declara realmente como un char (como en la definición de estilo de K & R anterior), se convierte implícitamente de nuevo a tipo de caracteres y se utiliza como un char dentro de la función. Así es como funcionó en los tiempos K & R, y así es como funciona hasta el día de hoy en la C moderna cuando la función no tiene prototipo o cuando se usan parámetros variados.

Ahora, cue en la C moderna, que tiene prototipos de función y usa syntax de definición de función de estilo moderno. Para preservar y reproducir la funcionalidad “tradicional” de strchr , como se describió anteriormente, no tenemos otra opción que declarar el parámetro de strchr como un int y convertirlo explícitamente a char dentro de la función. Esto es exactamente lo que observa en el código que citó. Esto es exactamente como la funcionalidad de strchr se describe en el estándar.

Además, si tiene una biblioteca heredada ya comstackda, donde strchr está definido en estilo K & R como se muestra arriba, y decidió proporcionar prototipos modernos para esa biblioteca, la statement adecuada para strchr sería

 char *strchr(const char *s, int c); 

porque int es lo que la implementación heredada anterior espera recibir físicamente como c . Declararlo con un parámetro char sería incorrecto.

Por este motivo, nunca verá funciones de biblioteca estándar “tradicionales” que esperan parámetros de tipo char , short o float . Todas estas funciones se declararán con parámetros de tipo int o double lugar.

Una razón fundamental detrás de la garantía estándar es que los punteros char y void * comparten los mismos requisitos de representación y alineación. Confiando en esta garantía, puede declarar malloc como una función de void * y luego usar esta statement con una versión heredada precomstackda de la biblioteca estándar donde malloc realmente devolvió char * .


Referencia: el razonamiento C99, versión 5.10

7.1.4 Uso de las funciones de la biblioteca
/ – /
Todos los prototipos de la biblioteca se especifican en términos de los tipos “ensanchados”: un argumento declarado anteriormente como char se escribe ahora como int. Esto garantiza que se pueda llamar a la mayoría de las funciones de la biblioteca con o sin un prototipo en el scope, manteniendo así la compatibilidad con el código pre-C89.

Creo que esto se puede atribuir a nada más que un accidente de la historia. Estás exactamente en lo cierto que char parece ser el tipo de datos obvio para el personaje que se busca.

En algunas situaciones en la biblioteca C, como la función getc() , se devuelve un valor int para la lectura de caracteres de la entrada. Esto no es un char porque puede devolverse un valor extra sin carácter ( EOF , generalmente -1) para indicar el final del flujo de caracteres.

El caso EOF no se aplica a la función strchr() , pero realmente no pueden retroceder y cambiar la statement de la función en la biblioteca C ahora.

En c, el tipo de un carácter literal es int . Por ejemplo: ‘a’ es de tipo int .

int c es el personaje que desea buscar. El carácter se pasa como un entero, pero de hecho solo se buscan los 8 bits más bajos. Por lo tanto, debe ser entregado a un char

La función strchr ve así:

 char *strchr(const char *s, int c){ while (*s != (char)c) if (!*s++) return 0; return (char *)s; } 

Como puede ver, hay un cast de int c a (char)c .

Ahora para responder a su pregunta, su char ch se convierte en un entero int c y se aplica como el valor ordinal de un personaje.

Entonces el siguiente progtwig debería estar bien:

 #include #include int main(void){ char *name = "Michi"; int c = 99; /* 99 is the ANSI code of c*/ char *ret = strchr(name, c); printf("String after %s\n", ret); return 0; } 

Pero lo siguiente no:

 #include #include int main(void){ char *name = "Michi"; char c = '99'; /* 99 is the ANSI code of c*/ char *ret = strchr(name, c); printf("String after %s\n", ret); return 0; } 

Debido a la multi-character character constant de multi-character character constant que se overflow in implicit constant conversion