Le warning -Wwrite-strings de gcc

Petit article pour parler d’un warning intéressant bien que non nécessaire de gcc : -Wwrite-strings.

La documentation de gcc précise l’effet de cette option :

-Wwrite-strings
When compiling C, give string constants the type const char[length] so that copying the address of one into a non-const char * pointer produces a warning. These warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it is just a nuisance. This is why we did not make -Wall request these warnings.

Testons son effet avec un bout de code trouvé sur Stackoverflow :

#include
#include

void somefunc(char buffer[10]) {
    int i;

    for (i = 0;   i < 10;   i++)
       buffer[i] = 0;
}

int main(void) {

    somefunc("Literal");
    return 0;
}

Si je compile ce code normalement, c’est-à-dire uniquement avec les options -Wall -Wextra, le compilateur ne génère aucun warning. En revanche, j’obtiens le message suivant en ajoutant l’option -Wwrite-strings :

D:\...\main.c|13|warning: passing argument 1 of 'somefunc' discards 'const' qualifier from pointer target type [enabled by default]|

C’est bien car on va essayer d’écrire dans un string litteral, ce qui va forcément pas bien marcher (doux euphémisme pour dire qu’il va y avoir une erreur de segmentation). Bien que le warning ne le dise pas explicitement, il attire quand même l’œil sur un problème de type : un pointeur possède le qualificatif const (le paramètre réel) et l’autre non (le paramètre formel). Comme il est bien sûr interdit d’ignorer un warning sans avoir une bonne raison, on se rendra compte du problème.

Il faut toutefois se méfier des faux positifs qui peuvent être générés. Il faut être rigoureux sur l’utilisation du mot-clé const dans les prototypes de fonctions, comme dit par la documentation. Voici un exemple de faux positif donné par kwariz :

void print_string(char *str)
{
    printf("string : '%s'\n", str);
}

Si la fonction est appelée avec une string litteral en paramètre, comme exemple ainsi print_string("Hello world");, le compilateur émettra un warning. En effet, le mot-clé const n’est pas respecté mais ici, ce n’est pas grave puisqu’on n’essaye pas de modifier la chaîne. La solution n’est en revanche pas d’ignorer le warning ou d’enlever l’option : il faut rajouter le mot-clé const dans le prototype de la fonction puisque la zone pointée n’est pas modifiée. Cela supprimera le warning et ne posera pas de soucis si la fonction est appelée avec une chaine modifiable. Le code suivant ne produit pas de warning par exemple :

#include
#include

void print_string(const char *str)
{
  printf("string : '%s'\n", str);
}

int main(void) {

    print_string("Literal");

    char msg[] = "Not litteral";
    print_string(msg);
    return 0;
}

Bon ajout de const et au revoir quelques erreurs de segmentation 🙂

3 Réponses

  1. gallier2

    Très bonne explication, parfait. J’ajouterais que c’est une des options les plus utiles que j’ai pu utiliser sur notre projet (~220 000 lignes de C). Quand j’ai ajouté l’option, ça m’a permis de détecter une bonne dizaine de bugs qui ne s’étaient pas encore manifestées en prod. Le fait de rendre les fonctions ‘const correct’ a permis de révéler les endroits où on assumait des choses qui n’étaient pas vraies.

    J’aime

    2 juillet 2013 à 6:23

    • Merci pour ce retour d’expérience qui confirme une utilité réelle de cette option !

      J’aime

      3 juillet 2013 à 8:10

  2. Pingback: Caster, c’est mal | Pierre Gradot

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.