Que signifie cette erreur? Je ne peux pas le résoudre en aucune façon.
avertissement: conversion obsolète de la constante de chaîne en 'char *' [-Wwrite-strings]
programming
arduino-ide
c
Federico Corazza
la source
la source
Réponses:
Comme d'habitude, je vais fournir un peu d'informations techniques de fond sur le pourquoi et le comment de cette erreur.
Je vais inspecter quatre façons différentes d'initialiser les chaînes C et voir quelles sont les différences entre elles. Ce sont les quatre voies en question:
Maintenant, pour cela, je vais vouloir changer la troisième lettre "i" en "o" pour en faire "Thos est du texte". Cela pourrait, dans tous les cas (on pourrait penser), être réalisé par:
Voyons maintenant ce que fait chaque façon de déclarer la chaîne et comment cette
text[2] = 'o';
déclaration affecterait les choses.D' abord la façon la plus souvent observée:
char *text = "This is some text";
. Qu'est-ce que cela signifie littéralement? Eh bien, en C, cela signifie littéralement "Créez une variable appeléetext
qui est un pointeur en lecture-écriture vers ce littéral de chaîne qui est conservé dans un espace en lecture seule (code)". Si l'option est-Wwrite-strings
activée, vous obtenez un avertissement, comme indiqué dans la question ci-dessus.Fondamentalement, cela signifie "Avertissement: vous avez essayé de créer une variable qui est en lecture-écriture vers une zone dans laquelle vous ne pouvez pas écrire". Si vous essayez de définir le troisième caractère sur "o", vous essayez en fait d'écrire dans une zone en lecture seule et les choses ne seront pas agréables. Sur un PC traditionnel avec Linux qui se traduit par:
Maintenant , le second:
char text[] = "This is some text";
. Littéralement, en C, cela signifie "Créer un tableau de type" char "et l'initialiser avec les données" Ceci est du texte \ 0 ". La taille du tableau sera suffisamment grande pour stocker les données". Donc, cela alloue réellement de la RAM et copie la valeur "This is some text \ 0" dedans au moment de l'exécution. Aucun avertissement, aucune erreur, parfaitement valable. Et la bonne façon de le faire si vous voulez pouvoir modifier les données . Essayons d'exécuter la commandetext[2] = 'o'
:Cela a fonctionné parfaitement. Bien.
Maintenant , la troisième voie:
const char *text = "This is some text";
. Encore une fois, le sens littéral: "Créez une variable appelée" texte "qui est un pointeur en lecture seule vers ces données dans la mémoire en lecture seule.". Notez que le pointeur et les données sont désormais en lecture seule. Aucune erreur, aucun avertissement. Que se passe-t-il si nous essayons d'exécuter notre commande de test? Eh bien, nous ne pouvons pas. Le compilateur est maintenant intelligent et sait que nous essayons de faire quelque chose de mal:Il ne compilera même pas. Les tentatives d'écriture dans la mémoire morte sont désormais protégées car nous avons indiqué au compilateur que notre pointeur est sur la mémoire morte. Bien sûr, il n'a pas avoir à pointer vers la mémoire en lecture seule, mais si vous pointez à la mémoire (RAM) en lecture-écriture que la mémoire sera toujours protégé d'être écrit par le compilateur.
Enfin , la dernière forme:
const char text[] = "This is some text";
. Encore une fois, comme auparavant,[]
il alloue un tableau dans la RAM et y copie les données. Cependant, il s'agit maintenant d'un tableau en lecture seule. Vous ne pouvez pas y écrire car le pointeur est marqué commeconst
. Tenter d'y écrire entraîne:Donc, un bref résumé de notre situation:
Ce formulaire est totalement invalide et doit être évité à tout prix. Cela ouvre la porte à toutes sortes de mauvaises choses qui se produisent:
Ce formulaire est le bon formulaire si vous souhaitez rendre les données modifiables:
Ce formulaire est le bon formulaire si vous voulez des chaînes qui ne seront pas modifiées:
Cette forme semble gaspiller de la RAM mais elle a ses utilisations. Il vaut mieux l'oublier pour l'instant.
la source
PROGMEM
,PSTR()
ouF()
. Ainsi,const char text[]
n'utilise pas plus de RAM queconst char *text
.(const char *)(...)
casting. Aucun effet réel si la carte n'en a pas besoin, mais une grande économie si vous portez ensuite votre code sur une carte qui en a besoin.Pour développer l'excellente réponse de Makenko, il y a une bonne raison pour laquelle le compilateur vous en avertit. Faisons un croquis de test:
Nous avons ici deux variables, foo et bar. Je modifie l' un de ceux de setup (), mais vois le résultat:
Ils ont tous deux changé!
En fait, si nous regardons les avertissements, nous voyons:
Le compilateur sait que c'est douteux, et c'est vrai! La raison en est que le compilateur s'attend (raisonnablement) à ce que les constantes de chaîne ne changent pas (car ce sont des constantes). Ainsi, si vous faites référence à la constante de chaîne
"This is some text"
plusieurs fois dans votre code, il est autorisé d'allouer la même mémoire à chacun d'eux. Maintenant, si vous en modifiez un, vous les modifiez tous!la source
*foo
et l'*bar
utilisation de différentes "constantes" de chaîne empêcheraient-elles cela de se produire? En outre, en quoi est-ce différent de ne pas mettre de chaînes du tout, commechar *foo;
:?new
,strcpy
etdelete
).Soit arrêtez d'essayer de passer une constante chaîne où une fonction prend un
char*
, soit changez la fonction pour qu'elle prenne un à laconst char*
place.Les chaînes comme "chaîne aléatoire" sont des constantes.
la source
Exemple:
Avertissement:
La fonction
foo
attend un char * (qu'elle peut donc modifier) mais vous passez un littéral de chaîne, qui ne doit pas être modifié.Le compilateur vous avertit de ne pas le faire. Étant obsolète, il peut passer d'un avertissement à une erreur dans une future version du compilateur.
Solution: faites en sorte que foo prenne un caractère const *:
Les versions plus anciennes de C (et C ++) vous permettent d'écrire du code comme mon exemple ci-dessus. Vous pouvez créer une fonction (comme
foo
) qui imprime quelque chose que vous lui transmettez, puis transmettre une chaîne littérale (par exemple.foo ("Hi there!");
)Cependant, une fonction qui prend
char *
comme argument est autorisée à modifier son argument (c'est-à-dire à modifierHi there!
dans ce cas).Vous pourriez avoir écrit, par exemple:
Malheureusement, en transmettant un littéral, vous avez maintenant potentiellement modifié ce littéral afin que "Salut!" c'est maintenant "Au revoir" qui n'est pas bon. En fait, si vous avez copié dans une chaîne plus longue, vous risquez d'écraser d'autres variables. Ou, sur certaines implémentations, vous obtiendrez une violation d'accès car "Salut!" peut avoir été placé dans la RAM en lecture seule (protégée).
Ainsi, les rédacteurs du compilateur déconseillent progressivement cette utilisation, de sorte que les fonctions auxquelles vous transmettez un littéral doivent déclarer cet argument comme
const
.la source
can not
être modifié?J'ai cette erreur de compilation:
Veuillez remplacer cette ligne:
#define TIME_HEADER "T" // Header tag for serial time sync message
avec cette ligne:
#define TIME_HEADER 'T' // Header tag for serial time sync message
et la compilation se passe bien.
la source