Redéfinition d'une variable entre plusieurs fichier .c ?

Le problème exposé dans ce sujet a été résolu.

Typiquement, en changeant la valeur de tes variables globales, si tu le fais en dehors de fonctions Bref, les variables globales, c’est à éviter.

Lyph

Sauf erreur de ma part, on ne peut pas coder une instruction en dehors d’une fonction en C (hormis une déclaration de variable + initialisation avec une constante). Puisque rien ne dirait quand l’exécuter ou dans quel ordre. C’est d’ailleurs pour ça qu’on ne peut pas déclarer de variable globale comme ça : int toto = titi; : il faut initialiser avec des constantes pour que chaque initialisation soit indépendantes des autres lignes de code. (bon je suis débutant je ne sais pas si les termes que j’emploie sont précis)

+1 -0

On a déjà eu le débat avec adri1. const ici.

Bref, const est assez cohérent en C, juste il devrait pas s’appeler const.

+1 -0

Humpf. Il faudrait que je fasse un billet sur toutes les règles de merde sur les différences entre les constant expressions et consorts en C comme j’ai pu faire pour l’initialisation. C’est tout sauf simple (sans même parler de toutes les libertés que prennent les compilateurs sur ce qui en est fait derrière).

Ça m’intéresse !
Pour moi const c’est juste immuable ?! Je vois pas trop de quoi tu parles.

Mais je sais que tu sais de quoi tu parles, c’est ton domaine alors du coup, j’adorerais avoir un article là-dessus.

+0 -0

Pour moi const c’est juste immuable ?! Je vois pas trop de quoi tu parles.

Ben ça déjà c’est vrai uniquement quand c’est appliqué à un objet. Si tu as un code comme:

void foo(int const* p){
  *(int*) p = 42 ;
}

Ce n’est pas forcément un undefined behavior, si p pointe sur un objet qui n’est pas const, c’est OK.

j’adorerais avoir un article là-dessus.

Autant si pour l’initialisation, ça avait été assez facile parce que je venais de faire le taf de décortiquer tout ça dans la norme, pour const c’est plus dur, déjà parce qu’il y a littéralement des centaines d’occurrences de cette chaîne dans la norme :'(

Mais du coup, si quelqu’un peut me confirmer qu’il n’y a pas de fautes dans ce qu’il me semble avoir compris par rapport au sujet de base :

  • si une variable est déclarée dans un fichier .c de la bibliothèque standard, et que par inadvertance, je déclare dans mon code une variable globale du même nom, alors ça déclenche une erreur de compilation ? D’où une question subsidiaire : on peut exclure des fichier de la librairie standard d’un projet ? Comment ? Est-ce que les fichiers de la librairie standard dépendent les un des autres ? (genre si j’en vire un, je dois en virer d’autres pour que ça compile ?).

  • certaines variables de librairie (comme errno) sont en fait des macrofonctions, et c’est pour cela qu’elles n’existent que là où on a inclus le header, car les macro sont traitées par le préprocesseur ?

+0 -0
  • si une variable est déclarée dans un fichier .c de la bibliothèque standard, et que par inadvertance, je déclare dans mon code une variable globale du même nom, alors ça déclenche une erreur de compilation ?
AScriabine

Si par « déclarée » tu veux dire « définie », alors oui, il y aura une erreur de compilation parce que tu définis deux fois une même variable.

D’où une question subsidiaire : on peut exclure des fichier de la librairie standard d’un projet ? Comment ? Est-ce que les fichiers de la librairie standard dépendent les un des autres ? (genre si j’en vire un, je dois en virer d’autres pour que ça compile ?).

AScriabine

Alors, techniquement, oui, MAIS :

  • Si tu veux carrément supprimer un fichier de la bibliothèque standard il te faudra soit t’y lier statiquement en retirant le fichier de l’archive (sous Linux se sont des fichiers .a qui sont gérés via la commande ar, un ancêtre de tar) soit recompiler la bibliothèque standard sans ce fichier.
  • Si tu veux simplement que ta variable ou fonction « écrase » celle de la bibliothèque standard, le linker supporte des options en ce sens (je connais surtout --wrap pour les fonctions, mais il doit aussi y avoir moyen pour les variables).

Cela étant ce n’est globalement pas une bonne idée, tu risques de te casser les dents sur des interdépendances ou autres joyeusetés. C’est quand même plus simple de juste choisir un autre nom. :p

Note, petite remarque en passant : si tu ne souhaites pas une variable globale (disponible dans tous les fichiers .c du programme), mais une variable uniquement utilisable dans un fichier .c, alors il te suffit de précéder sa définition du mot-clé static et de placer cette définition avant tout autre déclarations (ou définitions potentielles).

/* main.c */
#include <stdio.h>

static int toto = 0;
#include "toto.h"

int
main(void) {
        printf("%d\n", toto);
        print_toto();
        return 0;
}
/* toto.h */
#ifndef TOTO_H
#define TOTO_H

extern int toto;

extern void print_toto(void);

#endif /* TOTO_H */
/* toto.c */
#include <stdio.h>
#include "toto.h"

int toto = 10;

void
print_toto(void) {
        printf("%d\n", toto);
}

Cet exemple affichera 0 puis 10. Note que la variable définie dans main.c n’est utilisable que dans ce fichier. Tous les autres qui incluront toto.h ferons référence à la variable éponyme définie dans toto.c.

Ceci étant dit, il est très peu probable que tu entres en conflit avec une variable globale de la bibliothèque standard pour la simple raison qu’elle en défini (potentiellement) à ma connaissance 5 :

  • errno ;
  • math_errhandling ;
  • stdin ;
  • stdout ; et
  • stderr.

Et encore, ce ne sont pas forcément des variables, c’est juste que ces identificateurs sont réservés. Note qu’il en va aussi de même pour des noms de types ou autre comme bool qui est défini dans <stdbool.h>. Il faut juste faire attention aux identificateurs définis par chaque en-tête.

  • certaines variables de librairie (comme errno) sont en fait des macrofonctions, et c’est pour cela qu’elles n’existent que là où on a inclus le header, car les macro sont traitées par le préprocesseur ?
AScriabine

Le préprocesseur parcours aussi bien les fichiers d’en-tête que les fichiers source. La raison pour laquelle la macro est dans un fichier d’en-tête est simplement pour que tu puisses l’utiliser dans d’autres fichiers source.

Autant si pour l’initialisation, ça avait été assez facile parce que je venais de faire le taf de décortiquer tout ça dans la norme, pour const c’est plus dur, déjà parce qu’il y a littéralement des centaines d’occurrences de cette chaîne dans la norme :'(

Ksass`Peuk

Boh ça va, tu veux qu’on parle du mot-clé restrict ? :p
Note on peut faire ça à deux si tu veux. ;)

+3 -0

Boh ça va, tu veux qu’on parle du mot-clé restrict ?

Le pire avec restrict c’est qu’il y a une section "6.7.3.1 Formal definition of restrict" qui est tellement formelle qu’après l’avoir passé à lire à trois collègues différents, qui bossent tous sur des méthodes formelles, aucun de nous n’avait la même compréhension de la section en question …

Boh ça va, tu veux qu’on parle du mot-clé restrict ?

Le pire avec restrict c’est qu’il y a une section "6.7.3.1 Formal definition of restrict" qui est tellement formelle qu’après l’avoir passé à lire à trois collègues différents, qui bossent tous sur des méthodes formelles, aucun de nous n’avait la même compréhension de la section en question …

Ksass`Peuk

Ha ha ! :D
M’étonne pas, cette définition est une horreur. ^^'

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte