Pourquoi le type d’argument de `putchar ()`, `fputc ()` et `putc ()` n’est pas `char`?

Est-ce que quelqu’un sait pourquoi le type d’argument de putchar() , fputc() et putc() n’est pas un caractère, mais le type d’argument de putwchar() , fputwc() et putwc() est wchar_t ? Voir aussi ceci et cela .

La réponse est “inheritance” (ou “histoire”). Avant la norme C90, il n’y avait pas de prototypes de fonctions et tous les arguments de toutes les fonctions étaient soumis à des règles de promotion par défaut. Un caractère était donc automatiquement passé en tant que int ( short était promu en int aussi, et float en double , et de même pour les types non signés ). La norme ne pouvait pas se permettre de casser le code existant, elle a donc conservé ce type pour ces fonctions. Cela fait très peu de différence dans la pratique. La valeur que vous transmettez sera traitée comme un type de caractère même si vous transmettez une valeur hors limites. La spécification de fputc(int c, FILE *stream) dit:

La fonction fputc écrit le caractère spécifié par c (converti en caractère unsigned char ) dans le stream de sortie pointé par stream

Règles de promotion par défaut

§6.5.2.2 Appels de fonction

¶6 Si l’expression qui désigne la fonction appelée a un type qui n’inclut pas de prototype, les promotions d’entier sont effectuées sur chaque argument, et les arguments de type float sont promus au double. Celles-ci sont appelées les promotions d’arguments par défaut.

¶7… La notation de points de suspension dans un déclarateur de prototype de fonction provoque l’arrêt de la conversion du type d’argument après le dernier paramètre déclaré. Les promotions d’argument par défaut sont effectuées sur les arguments de fin.

Les promotions entières sont définies au § 6.3.1.

¶2 Les éléments suivants peuvent être utilisés dans une expression partout où un int ou un unsigned int peut être utilisé:

  • Un object ou une expression de type entier (autre que int ou unsigned int ) dont le rang de conversion d’entier est inférieur ou égal au rang d’ int et de unsigned int .
  • Un champ de bits de type _Bool , int , signed int ou unsigned int .

Si un int peut représenter toutes les valeurs du type d’origine (comme le limite la largeur, pour un champ de bits), la valeur est convertie en un int ; sinon, il est converti en un unsigned int . Celles-ci sont appelées promotions entières . 58) Tous les autres types ne sont pas modifiés par les promotions de nombre entier.

¶3 Les promotions sur les entiers conservent la valeur, y compris le signe. Comme discuté plus tôt, si un caractère “simple” est traité comme signé est défini par l’implémentation.

58) Les promotions d’entier sont appliquées uniquement: dans le cadre des conversions arithmétiques habituelles, à certaines expressions d’argument, aux opérandes des opérateurs unaire + , - et ~ , et aux deux opérandes des opérateurs de décalage, spécifiés par leurs opérateurs respectifs. sous-paragraphes.

Les rangs entiers sont définis au ¶1 de la section en 10 points.

Je pense que la réponse de Jonathan est trop simple. Les choses sont légèrement plus rationnelles. Je pense qu’aucune des fonctions de bibliothèque manipulant des caractères uniques ne fonctionne avec char (uniquement avec int ), car même si certaines d’entre elles n’utilisent pas EOF , nous ne pouvons pas définir son caractère char sans obtenir des avertissements de conversion de type tels que

 void f(char c) { ... ... char x = 't'; f((unsigned char)x); ... warning: conversion to 'char' from 'unsigned char' may change the sign of the result 

(Parce que les gens transtypent généralement char non signé pour garantir la portabilité du code, compte tenu du fait que la signature de char est indéfinie.) La seule option était donc de le rendre int .