Pourquoi strchr prend-il un int pour trouver le caractère?

La fonction strchr dans la bibliothèque standard C recherche un caractère dans une chaîne, mais sa signature prend un int pour le caractère de recherche. Dans ces deux implémentations que j’ai trouvées, l’implémentation convertit cet int en un caractère:

 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; } 

Quelqu’un sait-il pourquoi? Pourquoi ne pas simplement prendre un caractère en tant que paramètre?

Les raisons en sont purement historiques. Notez que jadis le langage C (K & R C), le prototype de fonction n’existait pas. Une fonction strchr à cette époque serait déclarée comme

 char *strchr(); 

et défini dans le style K & R comme

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

Cependant, en langage C (dans K & R C et également dans le moderne), si la fonction est déclarée sans prototype (comme indiqué ci-dessus), les parameters passés dans chaque appel de fonction sont soumis à ce qu’on appelle des promotions d’argument par défaut . Dans les promotions d’argument par défaut, tout type d’intégrale inférieur à int (ou unsigned int ) est toujours converti en int (ou unsigned int ). En d’autres termes, lorsque les parameters ne sont pas déclarés, chaque fois que vous transmettez une valeur de caractère en tant qu’argument, cette valeur est implicitement convertie en int et effectivement transmise physiquement en tant int . La même chose est vraie pour le short . (BTW, float est converti en double par la promotion des arguments par défaut). Si, à l’intérieur de la fonction, le paramètre est réellement déclaré en tant que caractère (comme dans la définition de style K & R ci-dessus), il est implicitement reconverti en type de caractère et utilisé en tant que caractère à l’intérieur de la fonction. C’est ainsi que cela fonctionnait à l’époque des K & R, et c’est ainsi qu’il fonctionne à ce jour dans le C moderne, lorsque la fonction n’a pas de prototype ou lorsque des parameters variadiques sont utilisés.

Maintenant, cue dans le C moderne, qui a des prototypes de fonction et utilise la syntaxe de définition de fonction de style moderne. Afin de préserver et de reproduire la fonctionnalité “traditionnelle” de strchr , comme décrit ci-dessus, nous n’avons d’autre choix que de déclarer le paramètre de strchr tant strchr et de le convertir explicitement en caractère dans la fonction. C’est exactement ce que vous observez dans le code que vous avez cité. C’est exactement comme la fonctionnalité de strchr est décrite dans la norme.

De plus, si vous avez une bibliothèque héritée déjà compilée, où strchr est défini dans le style K & R, comme indiqué ci-dessus, et que vous avez décidé de fournir des prototypes modernes pour cette bibliothèque, la déclaration appropriée pour strchr serait:

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

parce que int est ce que l’implémentation héritée ci-dessus s’attend à recevoir physiquement en tant que c . Le déclarer avec un paramètre char serait incorrect.

Pour cette raison, vous ne verrez jamais les fonctions de bibliothèque standard “traditionnelles” dans l’attente de parameters de type char , short ou float . Toutes ces fonctions seront déclarées avec des parameters de type int ou double place.

La garantie standard que les pointeurs de caractères et les points void * partagent les mêmes exigences de représentation et d’alignement est tout à fait la même. En vous fiant à cette garantie, vous pouvez déclarer malloc tant que fonction void * -returning, puis utiliser cette déclaration avec une version pré-compilée de la bibliothèque standard où malloc effectivement renvoyé char * .


Référence: la justification C99, version 5.10

7.1.4 Utilisation des fonctions de la bibliothèque
/ – /
Tous les prototypes de bibliothèque sont spécifiés en termes de types «élargis»: un argument précédemment déclaré comme char est maintenant écrit comme int. Cela garantit que la plupart des fonctions de bibliothèque peuvent être appelées avec ou sans prototype, ce qui permet de conserver une compatibilité ascendante avec le code antérieur à C89.

Je pense que cela ne peut être atsortingbué qu’à un accident de l’histoire. Vous avez parfaitement raison, car il semble que le type de données évident à utiliser pour le personnage recherché.

Dans certaines situations de la bibliothèque C, telles que la fonction getc() , une valeur int est renvoyée pour le caractère lu à partir de l’entrée. Ce n’est pas un caractère car une valeur non-caractère supplémentaire ( EOF , généralement -1) peut être renvoyée pour indiquer la fin du stream de caractères.

Le cas EOF ne s’applique pas à la fonction strchr() , mais ils ne peuvent pas vraiment revenir en arrière et changer la déclaration de la fonction dans la bibliothèque C.

En c, le type d’un caractère littéral est int . Par exemple: ‘a’ est de type int .

int c est le caractère que vous souhaitez rechercher. Le caractère est transmis sous forme d’entier, mais en fait, seuls les 8 bits les plus bas sont recherchés. Il devrait donc être remis à un personnage

La fonction strchr ressemble à ceci:

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

Comme vous pouvez le voir, il y a un cast de int c à (char)c .

Maintenant, pour répondre à votre question, votre caractère est converti en un entier entier et appliqué en tant que valeur ordinale d’un caractère.

Donc, le programme suivant devrait être OK:

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

Mais ce qui suit pas:

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

En raison de la multi-character character constant de multi-character character constant qui est un overflow in implicit constant conversion