Pourquoi ne passant char** comme const char** générer un avertissement?
J'ai reçu cet avertissement:
note: expected ‘const char **’ but argument is of type ‘char **’
Pour l'instant, je suis de passage des arguments par moulage à const char **
. Est-il un autre moyen que je peux me débarrasser de lui?
- Pourriez-vous fournir le prototype de fonction que vous utilisez?
- Assurez-vous.
int CompareRecords(const char **, const char **, const int *, const int)
- et le code que vous chanter la fonction avec
Vous devez vous connecter pour publier un commentaire.
Réponse Courte
Vous pouvez en toute sécurité transtypage
char **
àconst char**
? Pas. (Pas sûr de toute façon), et la raison est bien plus subtile que vous ne le pensez. Pouvez-vous vous débarrasser d'une autre façon? Assurez-vous. Charger un tableau deconst char*
valeurs de votrechar*
valeurs et les transmettre à la place. (ou de modifier le destinataire de l'appel de prototype, mais c'est de la triche =P).Considérons le code suivant, qui fait essentiellement tout ce que vous êtes désireux sauf appeler une fonction. La ligne marquée illustre l'équivalent de point-de-cast
Il faut du temps pour vraiment regarder, et certes je ne l'avais pas vu au premier abord, soit. @sheu a fait un travail solide de l'attraper environ 24 heures avant que je vraiment réfléchi assez longtemps pour réaliser qu'il était la bonne (et je fait upvoted que répondre avant d'écrire celui-ci). Alors j'ai pensé qu'il avait tort à propos de la même époque, il pensait que sa réponse n'était pas applicable. S'avère que nous étions les deux mal sur ce saut, car il était juste la première fois, j'ai été mal la deuxième fois, et maintenant... pouah.
Sur VS2012 et VS2010 à la fois la ligne marquée signalera une erreur sans un plâtre. clang va le compiler avec un avertissement en C, mais le permettent (que j'ai trouvé surprenant). Donné, vous n'avez vraiment pas de sortir de votre endroit heureux de le casser, mais il est encore aucun-le-moins cassé.
Le reste de ce qui est une diatribe sur l'identification des types de pointeur, leur constness, et ce qui est équivalent à ce qui.
Longue Diatribe sur les Pointeurs Et Const
L'avertissement est parce que
char **
etconst char **
ne sont pas équivalentes (duh). Pour être correct, il pourrait résoudre le prototype (l'appelé), ou de fixer l'appelant (par le chargement d'un tableau deconst char *
et passant). Mais vous pouvez en toute sécurité transtypage de la première à la seconde? Hmmm....Rappelez-vous, par la norme
const
va à l'élément immédiatement à son gauche. Déclarant sur le plus à gauche d'un type de données est un concept que la langue prend en charge, mais souvent introduit de la confusion ou de problèmes. Comme une règle-de-pouce, siconst
apparaît à l'extrême-gauche d'un decl immédiatement avant que le type, il s'applique aux données type; pas ultérieures pointeur (le cas échéant). Lorsqu'il apparaît à la droite de rien elle s'applique immédiatement à gauche decl-partie, que ce soit un type de données de la partie ou un pointeur de la partie, mais peu importe ce qu'elle s'applique seulement à un unique partie.Une pléthore d'échantillons suit:
Pas D'Indirection:
Simple Indirection:
Double Indirection:
Et de cours qui peuvent quitter la maison sans...
Alors, comment cela affecte votre question? Lors de la compilation de ce code en C, sans un casting, vous aurez un avertissement du compilateur (ou une erreur si la compilation avec
-Werror
). Lors de la compilation en C++, vous aurez tout simplement l'erreur, car le paramètre de la signature ne correspond pas. Mais pourquoi?Car ils ont pas d'équivalence directe:
Lors de la compilation avec clang, l'avertissement de C est donnée sous la forme:
VS2010 et VS2012 à la fois, sur l'autre main, jeter une erreur:
Il semble étrange, mais VS est en fait plus correct (merveilles jamais cesser).
Et qui fait beaucoup de sens. Niché dans la déclaration de type est le fait que le premier de ces ne permet pas de modification des données finales, la deuxième ne. À partir de ci-dessus, nous savons que
char **
etconst char **
(aka.char const **
), sont pas le même. Au bas de l'un est un pointeur vers uneconst char
, tandis que l'autre a un pointeur verschar
.char const * const *
EST sûr (puisque vous ne pouvez pas changer ce qu'il désigne). (J'ai vérifié cela à l'aide de OCaml type de système.) Malheureusement, la GCC gens semblent avoir utilisé le gros marteau approche en refusant de financer TOUTES ces plâtres, et Clang semble avoir copié.modifier: j'ai même répondu à la mauvaise question. Ma réponse est totalement hors de propos! M'ignorer s'il vous plaît.
edit 2: après le gentleman question demandeur précise à sa question, il s'avère que ma réponse est tout à fait pertinente. C est la vie.
C'est un amusement peu de C, ce qui est logique, si vous pensez assez dur à ce sujet.
Fondamentalement, la conversion:
n'est pas autorisé.
Pourquoi, me demanderez-vous? "Je suis en train de faire des choses plus const! C'est évidemment une bonne chose!"
Eh bien, pensez à ce sujet. Si cela était permis, alors:
BAM, vous êtes mort. Donc... pas 🙂
L'avertissement vous indique que la fonction que vous appelez attend le paramètre donné que
const char**
mais vous êtes de passage unchar**
paramètre. Pour se débarrasser de cet avertissement vous pourriezconst char**
const char**
(comme vous le faites actuellement)char**
const char * const *
, si la fonction n'a pas besoin de changer les caractères.