70 votes

Pourquoi est C++ me permettant d’assigner un const char en const char * ? !

À mon grand étonnement, il compile :

et il introduit un bug dans mon code. Heureusement, j’ai attrapé.

Est-ce intentionnel de C++, ou un bug du compilateur ? Y a-t-il une raison pourquoi le type de données est activement ignoré ?
Il a travaillé dans Visual C++ 2010 et GCC, mais je ne comprends pas pourquoi cela devrait fonctionner, compte tenu de l’incompatibilité de type de données évidentes. (La `` n’est pas nécessaire, non plus.)

69voto

Jerry Coffin Points 237758

Comme vous l'avez défini, nullchar est un entier constant d'expression avec la valeur 0.

Le C++03 norme définit un pointeur null constante comme: "Un pointeur null constante est une partie intégrante expression constante (5.19) rvalue de type entier qui donne zéro". Pour rendre une longue histoire courte, votre nullchar est un pointeur null constante, le sens qu'il peut être implicitement converti et assigné à n'importe quel pointeur.

Notez que tous ces éléments sont nécessaires pour que la conversion implicite d'un travail même si. Par exemple, si vous aviez utilisé l' '\1' au lieu de '\0', ou si tu avais pas précisé l' const à qualifier nullchar, vous ne seriez pas obtenir la conversion implicite -- votre mission aurait échoué.

L'Inclusion de cette conversion est intentionnel, mais largement connu comme indésirable. 0 comme un pointeur null constante a été hérité de C. je suis assez sûr que Bjarne et la plupart du reste de la norme C++ comité (et la plupart du C++ communauté en général) serait cher amour pour supprimer cette conversion implicite, mais ce serait détruire la compatibilité avec beaucoup de code C (probablement proche de tout).

28voto

curiousguy Points 2900

C'est une histoire ancienne: elle remonte à C.

Il n'y a pas d' null mot-clé dans C. Un pointeur null constante dans C est soit:

  • intégrante expression constante avec la valeur 0, comme 0, 0L, '\0' (rappelez-vous que char est une intégrale), (2-4/2)
  • une telle expression jeté à l' void*, comme (void*)0, (void*)0L, (void*)'\0', (void*)(2-4/2)

L' NULL macro (pas un mot!) se développe à un tel pointeur null constante.

Dans le premier C++ conception, l'intégrale de l'expression constante été accueilli comme un pointeur null constante. Récemment std::nullptr_t a été ajouté à C++.

En C++, mais pas en C, const variable de type intégral initialisé avec une partie intégrante expression constante est un élément constant de l'expression:

const int c = 3;
int i;

switch(i) {
case c: // valid C++
// but invalid C!
}

Ainsi, un const char initialisé avec l'expression '\0' est un pointeur null constante:

int zero() { return 0; }

void foo() {
    const char k0 = '\0',
               k1 = 1,
               c = zero();
    int *pi;

    pi = k0; // OK (constant expression, value 0)
    pi = k1; // error (value 1)
    pi = c; // error (not a constant expression)
}

Et vous pensez que ce n'est pas son langage de conception?


Mis à jour pour inclure les parties pertinentes de la norme C99... Selon le §6.6.6...

Une constante entière expression doit avoir de type entier et n'a d'opérandes qui sont les constantes entières, le dénombrement des constantes, des constantes de caractère, sizeof les expressions dont les résultats sont des constantes entières, et les constantes flottantes qui sont les immédiate des opérandes de jette. Opérateurs de Cast dans une constante entière expression ne convertir arithmétique types de types integer, sauf dans le cadre d'un opérande de l' sizeof de l'opérateur.

Quelques précisions pour C++-seuls les programmeurs:

  • C) utilise le terme de "constante" pour que les programmeurs en C++ savoir qu'une "littérale".
  • En C++, sizeof est toujours un moment de la compilation constante; mais C est de longueur variable, de tableaux, de sorte sizeof est parfois pas une compilation constante de temps.

Ensuite, nous voir §6.3.2.3.3 états...

Une constante entière expression avec la valeur 0, ou une expression en fonte de type void *, est appelé un pointeur null constante. Si un pointeur null constante, est converti en un type pointeur le pointeur résultant, appelé un pointeur null, c'est la garantie de comparer l'inégalité à un pointeur sur un objet ou une fonction.


Pour voir juste comment vieux cette fonctionnalité, voir l'identique en miroir des pièces dans la C98 standard...

§6.6.6

Une constante entière expression doit avoir de type entier et n'a d'opérandes qui sont des constantes entières, le dénombrement des constantes, des constantes de caractère, sizeof expressions dont les résultats sont des constantes entières, et les constantes flottantes qui sont les opérandes de jette. Opérateurs de Cast dans une constante entière expression est de convertir l'arithmétique types de types integer, sauf dans le cadre d'un opérande de l' sizeof de l'opérateur.

§6.3.2.3.3

Une constante entière expression avec la valeur 0, ou une expression en fonte de type void *, est appelé un pointeur null constante. Si un pointeur null constante, est converti en un type pointeur le pointeur résultant, appelé un pointeur null, c'est la garantie de comparer l'inégalité à un pointeur sur un objet ou une fonction.

14voto

Managu Points 5694

nullchar est un (compilation)expression constante, avec la valeur 0. Donc il est juste jeu pour la conversion implicite d'un pointeur null.

Plus en détail: je suis citant 1996 projet de norme ici.

char est un type intégral. nullchar est const, donc c'est une (au moment de la compilation) font partie intégrante de la constante d'expression, conformément à l'article 5.19.1:

5.19 expressions Constantes [expr.const]

1 Dans plusieurs endroits, C++ nécessite des expressions qui correspondent à une inte- gral ou constante d'énumération ... intégrante de la constante d'expression peut impliquer ... const variables ...

De plus, en nullchar évalue à 0, permettant d'être implicitement converti en un pointeur, conformément à la section 4.10.1:

4.10 Pointeur de conversions [conv.ptr]

1 intégrante expression constante (expr.const) rvalue de type entier qui prend la valeur de zéro (appelé un pointeur null constante) peut être con- transformés à un type de pointeur.

Peut-être une raison intuitive "pourquoi" ce pourrait être autorisée (juste à côté de ma tête), c'est que le pointeur de la largeur n'est pas spécifiée, et donc la conversion de toute la taille de l'intégrale de l'expression constante d'un pointeur null est autorisé.


Mis à jour avec les parties pertinentes de la (plus récente) C++03 standard... Selon le §5.19.1...

Une partie intégrante de la constante d'expression ne peut s'agir que des littéraux (2.13), les agents recenseurs, const des variables ou des données membres statiques de l'intégrale ou énumération des types de initialisé avec des expressions constantes (8.5), non-type de paramètres de modèle de l'intégrale ou énumération des types, et sizeof expressions.

Ensuite, nous étudions §4.10.1...

Un pointeur null constante est une partie intégrante expression constante (5.19) rvalue de type entier qui prend la valeur de zéro. Un pointeur null constante peut être converti en un type pointeur; le résultat est le pointeur null valeur de ce type et se distingue de tous les autres de la valeur de pointeur vers l'objet ou le pointeur de fonction type. Deux pointeur null valeurs du même type doit comparer l'égalité.

11voto

AndreyT Points 139512

Il compile pour la même raison, cette compile

const char *p = 0; // OK

const int i = 0;
double *q = i; // OK

const short s = 0;
long *r = s; // OK

Les Expressions de droite, tapez int et short, tandis que l'objet en cours d'initialisation est un pointeur. Cela vous étonne?

En langage C++ (comme en C) font partie intégrante des expressions constantes (Ciem) avec la valeur 0 ont un statut spécial (alors que le Ciem sont définies différemment dans le C et le C++). Ils qualifient de pointeur null constantes. Lorsqu'ils sont utilisés dans le pointeur de contextes, ils sont implicitement converti à null de pointeurs de type approprié.

Type char est un type intégral, pas très différente de l' int dans ce contexte, une const char objet initialisé par l' 0 est aussi un pointeur null constante en C++ (mais pas en C).

BTW, tapez bool en C++ est aussi partie intégrante de type, ce qui signifie qu'un const bool objet initialisé par l' false est aussi un pointeur null constante

const bool b = false;
float *t = b; // OK

6voto

Il n'est pas en ignorant le type de données. Ce n'est pas un bug. C'est profiter de la const vous mettre là, et de voir que sa valeur est un entier de 0 (char est un type entier).

Entier 0 est valide (par définition) de pointeur null constante, qui peut être converti en un type pointeur (qui devient le pointeur null).

Les raisons pourquoi vous voulez le pointeur null est d'avoir une valeur de pointeur qui "points de nulle part" et peut être vérifiable (c'est à dire que vous pouvez comparer un pointeur null à un nombre entier de 0, et vous obtiendrez le vrai en retour).

Si vous déposez le const, vous obtiendrez une erreur. Si vous mettez en double (comme avec beaucoup d'autres types integer; je suppose que les exceptions sont les seuls types qui peuvent être converties en const char* [par la surcharge des opérateurs de conversion]), vous obtiendrez un message d'erreur (même w/o const). Et ainsi de suite.

L'ensemble de la chose, c'est que, dans ce cas, votre mise en œuvre voit que vous êtes de retour null ptr constante; ce qui vous permet de convertir un type de pointeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X