Pourquoi C de caractères littéraux entiers au lieu de caractères?
En C++, sizeof('a') == sizeof(char) == 1
. Cela semble logique, puisque 'a'
est un caractère littéral, et sizeof(char) == 1
tel que défini par la norme.
En C cependant, sizeof('a') == sizeof(int)
. C'est, il semble que C les chaînes de caractères sont en fait des entiers. Quelqu'un sait-il pourquoi? Je peux trouver beaucoup de mentions de ce C caprice mais pas d'explication pour pourquoi il existe.
- sizeof serait juste de retour de la taille d'un byte ne serait-il pas? Ne sont pas un char et int de la même taille?
- C'est probablement le compilateur (et de l'architecture) à charge. Soin de dire ce que vous utilisez? La norme (au moins jusqu'à '89) a été très lâche.
- pas de. un char est toujours de 1 octet grand, donc sizeof('a') == 1 toujours (en c++), tandis qu'un int peut théoriquement être sizeof de 1, mais cela nécessiterait un octet ayant au moins 16 bits, ce qui est très rare 🙂 donc sizeof('a') != sizeof(int) est très probablement en C++ dans la plupart des implémentations
- ... alors qu'il est toujours mal en C.
- 'a' est un int en C - période. C y suis arrivé du premier C fait les règles. C++ a changé les règles. Vous pouvez argumenter que le C++ règles plus de sens, mais le changement de la C règles permettrait de faire plus de dégâts que de bien, de sorte que le C standard comité judicieusement n'a pas touché cette.
- Jonathan, juste pour être clair, mon "c'est toujours mal au C" n'est pas à dire que C est toujours mal:), cela signifie que sizeof('a') == sizeof(int) est toujours vrai dans C . votre commentaire ressemble vous un commentaire sur quelque chose je l'ai dit dans mon commentaire 🙂
Vous devez vous connecter pour publier un commentaire.
discussion sur même sujet
char
variable n'est pas un int, donc de la rendre un caractère constant de être un est un cas spécial. Et il est facile d'utiliser une valeur de caractère sans promotion:c1 = c2;
. Otoh, que,c1 = 'x'
est une baisse de la conversion. Plus important encore,sizeof(char) != sizeof('x')
, ce qui est grave, la langue de botch. Comme pour les jeux de caractères multioctets constantes: ils sont la raison, mais ils sont obsolètes.La question de départ est "pourquoi?"
La raison en est que la définition d'un caractère littéral a évolué et changé, tout en essayant de rester compatible avec le code existant.
Dans les jours sombres de début C il n'y avait pas des types à tous. Par moment j'ai d'abord appris à programmer en C, les types avaient été introduites, mais les fonctions n'ont pas de prototypes pour indiquer à l'appelant de ce que les types d'arguments ont été. Au lieu de cela il a été standardisé que tout ce passé comme un paramètre devrait être la taille d'un int (ce qui inclus tous les pointeurs) ou qu'il serait un double.
Cela signifie que lorsque vous écrivez la fonction, tous les paramètres qui n'étaient pas en double ont été stockées sur la pile comme ints, peu importe comment vous avez déclaré, et le compilateur de mettre le code dans la fonction pour gérer cela pour vous.
Cela a rendu les choses un peu incohérente, de sorte que lorsque K&R écrivit son célèbre livre, dans la règle qu'un caractère littéral serait toujours promu un int dans une expression, pas seulement un paramètre de la fonction.
Lorsque le comité ANSI première standardisé C, ils ont changé cette règle de manière un caractère littéral serait simplement un int, étant donné que cela semble un moyen plus simple de réaliser la même chose.
Quand le C++ a été conçu, toutes les fonctions ont été tenus d'avoir plein de prototypes (ce n'est pas encore obligatoire en C, bien qu'il est universellement accepté comme une bonne pratique). De ce fait, il a été décidé qu'un caractère littéral peut être stocké dans un char. L'avantage de cette en C++ est qu'une fonction avec un char paramètre et une fonction avec un paramètre de type int ont des signatures différentes. Cet avantage n'est pas le cas chez C.
C'est pourquoi ils sont différents. L'évolution...
void f(unsigned char)
Vsvoid f(signed char)
.f('a')
, vous voulez probablement résolution de surcharge de choisirf(char)
pour cet appel, plutôt que def(int)
. La taille relative deint
etchar
ne sont pas pertinentes, comme vous le dites.Je ne connais pas les raisons spécifiques pour lesquelles un littéral de caractère en C est de type int. Mais en C++, il y a une bonne raison de ne pas faire de cette façon. Considérez ceci:
Que vous attendez que l'appel à imprimer sélectionne la deuxième version de prendre un char. Ayant un caractère littéral étant un int rendrait impossible. Notez qu'en C++, les littéraux d'avoir plus d'un caractère toujours être de type int, bien que leur valeur est définie par l'implémentation. Donc,
'ab'
a typeint
, tandis que'a'
a typechar
.à l'aide de gcc sur mon MacBook, j'ai essayer:
qui lors de l'exécution donne:
qui suggère qu'un personnage est de 8 bits, comme vous pensez, mais un caractère littéral est un int.
En arrière quand C était écrit, le PDP-11 de la MACRO-11 de l'assemblée de la langue a:
Ce genre de chose est assez commun dans le langage d'assemblage - le faible taux de 8 bits tiendra le code de caractère, les autres bits égaux à 0. PDP-11 avait même:
Cela a fourni un moyen pratique pour charger des deux personnages dans la basse et haute octets de la 16 bits de registre. Vous pouvez ensuite écrire ailleurs, la mise à jour des données textuelles ou de l'écran de la mémoire.
Ainsi, l'idée de caractères d'être promu au registre de la taille est tout à fait normal et souhaitable. Mais, disons que vous avez besoin pour obtenir 'A' dans un registre pas dans le cadre de la codées en dur opcode, mais à partir de quelque part dans la mémoire principale contenant:
Si vous voulez le lire juste un 'A' à partir de ce mémoire principale dans un registre, qui aimeriez-vous lire?
Certains Processeurs ne peuvent directement prendre en charge la lecture d'une valeur 16 bits en 16 bits registre, ce qui signifierait une lecture à 20 ou 22 exigerait alors les bits de 'X' être nettoyé, et selon le boutisme de la CPU l'un ou l'autre aurait besoin de déplacement dans l'octet de poids faible.
Certains Processeurs peuvent exiger une mémoire aligné à lire, ce qui signifie que l'adresse la plus basse concernés doit être un multiple de la taille des données: vous pourriez être en mesure de lire les adresses, les 24 et 25, mais pas 27 et 28.
Donc, un compilateur de générer du code pour obtenir Un " a " dans le registre peut préférer à perdre un peu plus de mémoire et d'encoder la valeur 0 'A' ou 'A' 0 - en fonction de l'endianness, et aussi de s'assurer qu'il est correctement aligné (à savoir pas d'un drôle d'adresse de mémoire).
Ma conjecture est que C est tout simplement porté ce niveau de CPU centrée sur le comportement, la pensée de constantes de caractère occupant registre des tailles de mémoire, portant la commune d'évaluation de C comme un "assembleur de haut niveau".
(Voir 6.3.3 sur la page 6-25 de http://www.dmv.net/dec/pdf/macro.pdf)
Je me souviens de la lecture de K&R et voir un extrait de code qui permettrait de lire un caractère à la fois jusqu'à ce qu'il a frappé des expressions du FOLKLORE. Depuis, tous les caractères sont des caractères valides dans un fichier/flux d'entrée, cela signifie que les expressions du FOLKLORE ne peut pas être n'importe quelle valeur char. Ce que le code a été de mettre à la lecture de caractères en un entier (int), puis de tester pour les expressions du FOLKLORE, puis convertir un char si il n'était pas.
Je me rends compte ce n'est pas exactement la réponse à votre question, mais il serait un certain sens, pour le reste des chaînes de caractères pour être sizeof(int) si les expressions du FOLKLORE littérale était.
Je n'ai pas vu une justification (C char littéraux être int types), mais voici quelque chose de Stroustrup avait à dire à ce sujet (de la Conception et de l'Évolution 11.2.1 - Fine-Grain Résolution):
Donc, pour la plupart, il ne devrait causer aucun problème.
C'est le bon comportement, appelé "font partie intégrante de la promotion". Il peut arriver dans d'autres cas également (principalement des opérateurs binaires, si je me souviens bien).
EDIT: Juste pour être sûr, j'ai vérifié ma copie de Expert de la Programmation en C: Secrets Profonds, et je confirme qu'un char littérale n'est pas commencer avec un type int. C'est d'abord de type char mais quand il est utilisé dans un expression, il est promu à un int. Ce qui suit est cité dans le livre:
An integer character constant has type int
". Soit "au plus Profond des Secrets" est incorrect ou vous avez simplement mal compris.La raison historique à cela est que C, et de son prédécesseur, B, ont été à l'origine développé sur différents modèles de DEC PDP mini-ordinateurs avec différentes longueurs de mot, qui a soutenu 8 bits ASCII, mais ne pouvait effectuer l'arithmétique sur les registres. (Pas le PDP-11, cependant; c'est venu plus tard.) Les premières versions de C définie
int
être le natif word taille de la machine, et de toute valeur inférieure à unint
devait être élargie àint
afin d'être transmis vers ou à partir d'une fonction, ou utilisé dans un bit à bit, logique ou une expression arithmétique, parce que c'était la façon dont le matériel sous-jacent travaillé.C'est aussi pourquoi le entier les règles de la promotion continue à dire que tout type de données plus petit qu'un
int
est promuint
. C implémentations sont également autorisés à utiliser un complément de mathématiques au lieu de complément à deux, pour les mêmes raisons historiques. La raison que octal personnage s'échappe et les constantes octales sont des citoyens de première classe par rapport à l'hexagone de même que ceux au début de DÉCEMBRE les mini-ordinateurs de mot tailles divisible en trois octets morceaux mais pas de quatre octets des amuse-gueules.char
était exactement 3 octale longJe ne sais pas, mais je suppose que c'était plus facile à mettre en œuvre et il n'a pas vraiment d'importance. Il n'était pas jusqu'à ce que le C++ quand le type peut déterminer la fonction est appelée qu'il est nécessaire pour être fixé.
Je ne connaissais pas cet effet.
Avant de prototypes existé, rien de plus étroit qu'un int est converti en int lors de l'utilisation de ce comme un argument de fonction. Qui peut faire partie de l'explication.
char
àint
rendrait tout inutile pour les constantes de caractère à ints. Ce qui est significatif, c'est que la langue traite des constantes de caractère différemment (en leur donnant un autre type) dechar
variables, et ce qui est nécessaire est une explication de cette différence.Ce n'est tangentielle à la langue spec, mais dans le matériel du PROCESSEUR habituellement n'a qu'un seul registre de la taille -- 32 bits, disons -- et donc, chaque fois qu'il fonctionne en fait sur un char (par l'addition, la soustraction, ou le comparant) il y a une conversion implicite de type int lorsqu'il est chargé dans le registre. Le compilateur prend en charge correctement masquage et en déplaçant le nombre après chaque opération, de sorte que si vous ajouter, disons, 2 (unsigned char) 254, ça va enrouler autour de 0 au lieu de 256, mais à l'intérieur de la silicon c'est vraiment un int jusqu'à ce que vous enregistrer dans la mémoire.
C'est en quelque sorte un universitaire point, parce que la langue pourrait avoir spécifié un 8 bits type de littéral de toute façon, mais dans ce cas, la langue spec arrive à refléter plus fidèlement ce que le CPU est vraiment en train de faire.
(x86 wonks peut noter qu'il y a par exemple un natif addh op qui ajoute de la courte échelle registres en une seule étape, mais à l'intérieur du noyau RISC cela se traduit par deux étapes: ajouter les numéros, puis étendre signe, comme un ajout/extsh paire sur le PowerPC)
char
les variables de types différents. Automatique de promotions, qui reflètent le matériel, ne sont pas pertinents, ils sont en fait des anti-pertinent, parce quechar
variables sont automatiquement promus donc c'est pas une raison pour les chaînes de caractères ne pas être de typechar
. La vraie raison est multi-octets littéraux, qui sont maintenant obsolètes.