IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bibliothèques, systèmes et outils C Discussion :

Définitions multiples de mes constantes de couleurs !


Sujet :

Bibliothèques, systèmes et outils C

  1. #1
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 380
    Points : 19 062
    Points
    19 062
    Par défaut Définitions multiples de mes constantes de couleurs !
    Salut à tous.

    J'utilise une bibliothèque dans laquelle, j'ai déclaré d'une part des fonctions et d'autre part des constantes de couleurs.
    Ma bibliothèque se nomme "libmine".

    Ce qui me pose problème, ce sont mes constantes. Par contre, je n'ai pas de problèmes avec mes fonctions.
    Dans "libmine.c", j'ai mis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #include "libmine.h"
     
    T_COLOR         _black          = {  0,   0,   0};
    T_COLOR         _grey           = {128, 128, 128};
    T_COLOR         _white          = {255, 255, 255};
    Dans "libmine.h", j'ai mis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifndef __LIBMINE__
    #define __LIBMINE__
     
    typedef struct
    {
            char    red;
            char    green;
            char    blue;
    } T_COLOR;
     
    T_COLOR         _black;
    T_COLOR         _grey;
    T_COLOR         _white;
     
    #endif
    Je compile la bibliothèque. Aucun problème.

    Dans le programme "main.c", j'appelle l'include :
    J'obtiens la liste suivante des messages d'erreurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /usr/bin/ld*: /warehouse/Prog_C/09.Library//libmine.a(tft.o):(.data+0x808)*: définitions multiples de «*_white*»; main.o:(.bss+0x8)*: défini pour la première fois ici
    /usr/bin/ld*: /warehouse/Prog_C/09.Library//libmine.a(tft.o):(.data+0x80c)*: définitions multiples de «*_grey*»; main.o:(.bss+0x4)*: défini pour la première fois ici
    /usr/bin/ld*: /warehouse/Prog_C/09.Library//libmine.a(tft.o):(.bss+0xf0a0)*: définitions multiples de «*_black*»; main.o:(.bss+0x0)*: défini pour la première fois ici
    J'ai pourtant mis le warpper "#ifndef" afin d'éviter la duplication du contenu de "libmine.h".
    A tout hasard, je donne le makefile du main.c :
    Code Makefile : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    # ------------------------------- #
    #   Déclaration des Executables   #
    # ------------------------------- #
     
    RM      = @rm -f
    CC      = @gcc
    EX      = @chmod +x
     
    # -------------------------- #
    #   Déclaration des Objets   #
    # -------------------------- #
     
    SRC     = main.c
    OBJ     = main.o
    BIN     = tft18
     
    # ---------------------------- #
    #   Déclaration des Includes   #
    # ---------------------------- #
     
    INCS    = -I"/warehouse/Prog_C/09.Library/include/"
     
    # --------------------------------- #
    #   Déclaration des Bibliothèques   #
    # --------------------------------- #
     
    LIBS    = -L"/warehouse/Prog_C/09.Library/"
     
    # ------------------------------ #
    #   Déclaration des Paramètres   #
    # ------------------------------ #
     
    FLAG    = -O -Wall -Wextra -Wpedantic
    LOAD    = -lmine -lm
     
     
    # ------------------------------------ #
    #   Compilation et Edition des liens   #
    # ------------------------------------ #
     
    all: before $(BIN) after
     
    before:
            clear
            $(RM) $(OBJ)
            $(RM) $(BIN)
     
    $(BIN): $(OBJ)
            $(CC)    $(OBJ) $(LIBS) -o $(BIN) $(LOAD)
     
    $(OBJ): $(SRC)
            $(CC) -c $(SRC) $(INCS) -o $(OBJ) $(FLAGS)
     
    after:
            $(RM) $(OBJ)
            $(EX) $(BIN)
            @./$(BIN)
    Pourquoi ai-je ce problème que sur les constantes ?
    Je ne comprends pas pourquoi les déclaratives de mes fonctions ne me pose aucun problème.

    Comment résoudre mon problème ?

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  2. #2
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Bonjour,

    les variables globales en C … c'est parfois une plaie. Pour déclarer des variables globales et non les définir il faut utiliser le mot clé extern :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifndef __LIBMINE__
    #define __LIBMINE__
     
    typedef struct
    {
            char    red;
            char    green;
            char    blue;
    } T_COLOR;
     
    extern T_COLOR         _black;
    extern T_COLOR         _grey;
    extern T_COLOR         _white;
     
    #endif
    En C un peu plus moderne ou pourrait écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #pragma once
     
    typedef struct {
    	unsigned char red;
    	unsigned char green;
    	unsigned char blue;
    } T_COLOR;
     
    #define _COLOR(...) ( (T_COLOR) { __VA_ARGS__ } )
    //#define _COLOR(...) ( (T_COLOR) { .red=0, .green=0, .blue=0, __VA_ARGS__ } )
     
    static inline T_COLOR _GREY_LEVEL(unsigned char n) { return _COLOR(.red=n, .green=n, .blue=n); }
    static inline T_COLOR _BLACK() { return _GREY_LEVEL(0); }
    static inline T_COLOR _GREY() { return _GREY_LEVEL(128); }
    static inline T_COLOR _WHITE() { return _GREY_LEVEL(255); }
    #pragma once peut, dans certains cas, remplacer avantageusement les include guards classiques car l'espace de nom est moins pollué, et le compilo peut mieux optimiser les includes.
    La macro _COLOR sert à créer une structure anonyme bien initialisée. Dans sa seconde forme commentée tu peux y ajouter des valeurs par défaut.
    Les fonctions static inline remplacent avantageusement les macros et les variables globales car elles sont traçables au debug, et lors d'une compilation release seront complètement inexistantes (sauf cas particuliers) dans le binaire. Les compilos moderne seront assez smarts pour ne pas créer plein de variables temporaires et dans des cas comme ceux indiqués utiliseront directement une structure bien initialisée dès le compilation time.

  3. #3
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 380
    Points : 19 062
    Points
    19 062
    Par défaut
    Salut WhiteCrow.

    Merci pour les explications et les exemples.
    C'est la solution que je recherchais.

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Tu devrais rajouter static const dans les déclarations, pour en faire des constantes et non des variables, et résoudre le problème de "mutliple definitions of".

  5. #5
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    const ne rend pas l'objet qualifié constant … il ne fait qu'indiquer au compilo que l'on s'engage à ne pas le modifier, ce qui est différent.

    Pour avoir de «vraies constantes» il faut soit utiliser le préprocesseur et un #define ou une fonction (éventuellement static inline) qui renvoie toujours la même valeur (et que l'on pourra annoter comme const ou pure avec clang ou gcc). Dans ces cas le compilo arrive à en déterminer la valeur au moment de la compilation. Dans le cas d'une «constante donnée comme taille de tableau» seul un #define sera utile.

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Ouais enfin bon...

    Ce code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    typedef struct
    {
        char    red;
        char    green;
        char    blue;
    } T_COLOR;
     
    const T_COLOR _black = { 0, 0, 0};
     
    int main(void) {
        _black.red = 255;
    }
    lève une erreur :

    error: assignment of member 'red' in read-only object
    Alors, je veux bien qu'on peut caster ou faire des pointeurs incohérents en typage pour modifier ça (ce qui doit être un undefined behavior de toute façon), mais je pense quand même que c'est pas mal hein.

  7. #7
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Ça aurait pu être pas mal si cela n'avait pour conséquence de répandre des const un peu partout … parce que ta variable globale (ce qui en soit n'est pas forcément une bonne approche) en const que tu vas passer en paramètre à une fonction qui attend un TColot mais pas const … va provoquer un warning. Alors soit, tu peux qualifier ledit paramètre en const et ça va se propages encore plus loin … ou alors tu castes et le const ne sert plus à rien. Et je ne parle pas du cas où tu passeras un pointeur sur la variable globales …

    C n'est pas adapté à un const de ce genre parce que const signifie réellement «je m'engage à ne pas modifier ce que je qualifie» mais que le compilo n'as pas la capacité de le vérifier ou de le contraindre.const ne permet pas de créer une «vraie» constante considérée comme telle dès le compilation time.
    En revanche utiliser const pour les paramètres est un peu plus utile. const c'est juste un «read only» un peu mal foutu et surtout mal compris.

    La technique de «c'est une fonction qui renvoie une valeur anonyme» permet en revanche de pallier ces nombreux problèmes, et dans ce cas les compilo seront assez intelligents pour ne pas créer une pléthore de variables temporaire ou d'appels inutiles.

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Une fonction comme celle-ci ne provoque pas de warning, car on fait une copie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void print(T_COLOR c) {
        // ...
    }
    Une fonction comme celle-ci en revanche en génèrera un :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void print(T_COLOR* c) {
        // ...
    }
    Il faut effectivement faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void print(const T_COLOR* c) {
        // ...
    }
    Ce qui permet alors de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int main(void) {
        print(&_black);
    }
    Je veux bien qu'on soit en C et que je ne fais plus que du C++, mais pour moi, on est vraiment dans un cas typique de données constantes. La propagation des const est là pour ça. C'est le but même.

    Tu n'utilises jamais const en C ?

  9. #9
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Jamais pour définir une constante car const ne permet pas de le faire et n'est pas fait pour ça d'ailleurs.

    Imagine simplement qu'un champ de structure soit de type T_Color
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct {
        T_Point *center;
        double radius;
        T_Color *color;
    } T_Circle;
    Imagine en plus que tu aimes tellement les const et les variables globales qu'on retrouve quelque part dans le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    const T_Point _Origin = (T_Point) {.x=0, .y=0};

    Tu auras le choix soit d'utiliser tes const globales (en les castant) pour créer de nouveaux objets avec la possibilité de bug et modification non voulue desdites const globales, soit de copier les valeurs des const globales dans les primitives de création.
    Du coup ça va sévèrement limiter l'utilité du const.
    En revanche si tu as un simple #define ou une fonctions static inline qui renvoie un objet tu te libères de ces soucis. Dans ces cas tu as directement un littéral optimisable lors des phases compilation et d'édition des liens. Dans ton cas tu t'exposes à des bugs au runtime.

    Alors const, àmha, n'est réellement utile que pour qualifier un paramètre de fonction afin d'indiquer au compilo que tu t'engages à ne pas le modifier et qu'il peut allègrement faire toutes les optimisations qui lui sont permises. Bon si tu lui mens, tu te tire une balle dans le pied.
    C'est un peu comme restrict … dans les deux cas c'est un contrat que tu passes avec ton compilo.

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Tu auras le choix soit d'utiliser tes const globales (en les castant)
    Il faut arrêter avec ça : https://wiki.sei.cmu.edu/confluence/...+qualification

    Do not cast away a const qualification on an object of pointer type. Casting away the const qualification allows a program to modify the object referred to by the pointer, which may result in undefined behavior. See undefined behavior 64 in Appendix J of the C Standard.
    Ces mêmes guidelines recommandent d'ailleurs d'utiliser const. Voir https://wiki.sei.cmu.edu/confluence/...literal+values ou https://wiki.sei.cmu.edu/confluence/...utable+objects

    Il est d'ailleurs que c'est normal que ça se propage (citation du 2e lien) :

    Adding const qualification may propagate through a program; as you add const, qualifiers become still more necessary. This phenomenon is sometimes called const poisoning, which can frequently lead to violations of EXP05-C. Do not cast away a const qualification. Although const qualification is a good idea, the costs may outweigh the value in the remediation of existing code
    Commencer à mettre des const oblige à réfléchir très fortement à ses types. Et oui, c'est contraignant. Parfois peut-être trop, surtout dans une base de code existante.

    Ton exemple est incomplet à mon avis pour illustrer complètement ce que tu veux dire :

    - Pourquoi ta classe T_CIRCLE a besoin de pointer sur une couleur non constante ?
    - Est-ce que tu ne pourrais pas utiliser une couleur constante ?
    - Qu'est ce que ça apporterait comme bénéfice ou inconvénient ?
    - Pourquoi un pointeur d'ailleurs ?

    De plus, comment vas-tu faire matcher un pointeur sur T_COLOR avec un #define d'un T_COLOR ? Même question avec le retour d'une fonction (quelle soit static inline ou pas).

  11. #11
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Citation Envoyé par WhiteCrow Voir le message
    Tu auras le choix soit d'utiliser tes const globales (en les castant)
    Il faut arrêter avec ça : […]
    Je veux bien que tu exhibes tous les liens que tu veux, mais prends au moins toute mon argumentation en compte … parce que non seulement il y a un si avant mais aussi un soit après.

    Citation Envoyé par WhiteCrow Voir le message
    Imagine que [=si] [suit un exemple où on utilise un pointeur sur un objet dont le type pointé est le type de la constante]

    Tu auras le choix soit d'utiliser tes const globales (en les castant) pour créer de nouveaux objets avec la possibilité de bug et modification non voulue desdites const globales, soit de copier les valeurs des const globales dans les primitives de création.
    Donc, peut-être plus clairement, si on opte pour un tel design par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    include <stdio.h>
     
    struct color {
    	double R;
    	double G;
    	double B;
    };
     
    static const struct color _WHITE = (const struct color) {.R=1.0, .G=1.0, .B=1.0 };
     
    struct what_ever {
    	struct color *pcolor;
    	// …
    };
    Alors pour donner une valeur au champ pcolor en utilisant «la constante» on a le choix entre :
    • soit caster (pour faire taire un warning)
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      	//struct what_ever foo = (struct what_ever) {.pcolor=&_WHITE};
      	struct what_ever foo = (struct what_ever) {.pcolor=(struct color *)&_WHITE};
      et, comme je le notais, cela intriduit une «possibilité de bug et modification non voulue desdites const globales»
    • soit copier (pour oublier un const qui n'avait pas lieu d'être en premier lieu car mal utilisé, àmha)
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      struct what_ever bar = (struct what_ever) {.pcolor= (struct color[]) {_WHITE} };
      qui alourdit le code.



    Citation Envoyé par Bktero Voir le message
    Ton exemple est incomplet à mon avis pour illustrer complètement ce que tu veux dire :

    - Pourquoi ta classe T_CIRCLE a besoin de pointer sur une couleur non constante ?
    - Est-ce que tu ne pourrais pas utiliser une couleur constante ?
    - Qu'est ce que ça apporterait comme bénéfice ou inconvénient ?
    - Pourquoi un pointeur d'ailleurs ?

    De plus, comment vas-tu faire matcher un pointeur sur T_COLOR avec un #define d'un T_COLOR ? Même question avec le retour d'une fonction (quelle soit static inline ou pas).
    Alors dans l'ordre :
    • Pourquoi ta classe T_CIRCLE a besoin de pointer sur une couleur non constante ?
      Mon exemple précédent est sans doute plus parlant et n'introduit plus de distractions.

    • Est-ce que tu ne pourrais pas utiliser une couleur constante ?
      Es-tu en train de me dire que le const poisoning devrait aller jusqu'à rendre const tous les champs d'une structure dont le type serait celui d'une constante ?

    • Qu'est ce que ça apporterait comme bénéfice ou inconvénient ?
      heu … à quoi ?

    • Pourquoi un pointeur d'ailleurs ?
      Dans le cadre de l'exemple avec le cercle, pour partager la couleur entre plusieurs cercles … mais à la limite pourquoi pas ? le const poisoning interdirait-il l'utilisation de pointeurs sur un type pour lequel on aurait définit des constantes ?

    • De plus, comment vas-tu faire matcher un pointeur sur T_COLOR avec un #define d'un T_COLOR ? Même question avec le retour d'une fonction (quelle soit static inline ou pas).
      De la même manière que je copie une «constante globale (ou non) statique (ou non)» dans un objet anonyme dont je prends l'adresse.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      #define WHITE ((struct color) {.R=1.0, .G=1.0, .B=1.0})
       
      struct color white(void) {
      	return WHITE;
      }
       
      ...
       
      	struct what_ever baz = (struct what_ever) {.pcolor= (struct color[]) {WHITE} };
      	struct what_ever qux = (struct what_ever) {.pcolor= (struct color[]) {white()} };
      …
      Le static inline ne sert qu'à aider le compilo à optimiser les appels. C'est un moyen comme un autre «d'avoir des macros typées».


    Maintenant, très personnellement et de but en blanc, j'opterais sans doute pour une API plus proche de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    enum color_index { DEFAULT=0, BLACK=DEFAULT, /* ... */, WHITE };
     
    struct color color_RGB(double, double, double);
    struct color color_index(enum color_index index);
    // ....
     
    struct color *color_alloc(void);
    struct color *color_free(const struct color *);
    Tu remarqueras que je suis la const correctness avec ma fonction de libération de la mémoire d'un struct color* car libérer de la mémoire allouée ne modifie pas/ne devrait pas modifier ce qui est pointé … mais que cela va poser des problèmes (sans doute) avec le free qui lui, dans sa version standard, n'a pas ce qualificateur au paramètre … un «cast obligatoire en l'occurrence» qui indique bien la différence entre «const qui qualifierait une vraie constante» et «const qui indique au compilo qu'on s'engage à ne pas modifié ce qui est qualifié».

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par WhiteCrow Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    include <stdio.h>
     
    struct color {
    	double R;
    	double G;
    	double B;
    };
     
    static const struct color _WHITE = (const struct color) {.R=1.0, .G=1.0, .B=1.0 };
     
    struct what_ever {
    	struct color *pcolor;
    	// …
    };
    Alors pour donner une valeur au champ pcolor en utilisant «la constante» on a le choix entre :
    • soit caster (pour faire taire un warning)
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      	//struct what_ever foo = (struct what_ever) {.pcolor=&_WHITE};
      	struct what_ever foo = (struct what_ever) {.pcolor=(struct color *)&_WHITE};
      et, comme je le notais, cela intriduit une «possibilité de bug et modification non voulue desdites const globales»
    • soit copier (pour oublier un const qui n'avait pas lieu d'être en premier lieu car mal utilisé, àmha)
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      struct what_ever bar = (struct what_ever) {.pcolor= (struct color[]) {_WHITE} };
      qui alourdit le code.
    Ou alors, un peu de bon sens
    - se rendre que const est un mot-clé qui existe pour une très bonne raison et tout comme on n'est pas sencé ignorer les warnings, on va pas l'ignorer non plus
    - soit tu mets ton pointeur const, parce que tu utilises des couleurs prédéfinies, partagées, et n'es donc pas sencé les modifier
    - soit la couleur est une copie dans chaque cercle qui en fait ce qu'il veut, et la constante peut être utilisée comme valeur source à recopier

    Parce que bon justifier que le marteau est un mauvais outil parce qu'on peut pas visser avec, c'est un peu gros.
    Et si tu aimes tant tout caster et casser, pourquoi s'emmerder à utiliser des types alors qu'on pourrait tout mettre void* puis caster partout n'importe comment quand on veut ?

    Donc de ce que tu dis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    struct what_ever bar = (struct what_ever) {.pcolor= (struct color[]) {_WHITE} };
    Alourdit le code
    mais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct color white(void) {
    	return WHITE;
    }
     
    ...
     
    	struct what_ever baz = (struct what_ever) {.pcolor= (struct color[]) {WHITE} };
    	struct what_ever qux = (struct what_ever) {.pcolor= (struct color[]) {white()} };
    …
    est totalement ok
    Et assigner à un pointeur un truc à partir d'un define, ou d'une copie retournée par une fonction, donc temporaire, est au mieux cavalier.

    Et encore une fois c'est juste ton constat de départ qui est faux parce que soit tu utilises des constantes et n'as pas à les modifier, soit tu les utilises pour créer des copies et tu en fais ce que tu veux.
    Si tu utilises les constantes, tu peux les partager et utiliser les pointeurs pour ça, mais si tu comptes en faire des copies, c'est l'utilisation de pointeurs qui devrait être remis en cause.

    libérer de la mémoire allouée ne modifie pas/ne devrait pas modifier ce qui est pointé
    T'es sûr que tu es toujours en C ?
    Parce que libérer un pointeur, ça rend juste totalement invalide l'objet pointé, ce qui est une modification assez conséquente dudit objet.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Ou alors, un peu de bon sens
    - se rendre que const est un mot-clé qui existe pour une très bonne raison et tout comme on n'est pas sencé ignorer les warnings, on va pas l'ignorer non plus
    - soit tu mets ton pointeur const, parce que tu utilises des couleurs prédéfinies, partagées, et n'es donc pas sencé les modifier
    - soit la couleur est une copie dans chaque cercle qui en fait ce qu'il veut, et la constante peut être utilisée comme valeur source à recopier

    Parce que bon justifier que le marteau est un mauvais outil parce qu'on peut pas visser avec, c'est un peu gros.
    Et si tu aimes tant tout caster et casser, pourquoi s'emmerder à utiliser des types alors qu'on pourrait tout mettre void* puis caster partout n'importe comment quand on veut ?
    Historiquement const a été introduit trop rapidement en C, le WG14 ayant, toujours àmha, voulu trop c++ifier le c … il suffit de d'essayer d'être const correct et d'utiliser ne serait-ce qu'avec strcpy.
    Tu proposes d'autres design … soit. Mais ce n'est pas parce qu'il en existe d'autres que ça va faire avancer le schmilblick … ce n'est pas parce que tu n'as qu'un tournevis qu'il faut mettre des vis partout …
    Ensuite, comprends bien que je ne dis pas que c'est une bonne chose de caster à tour de bras, bien au contraire. Ce que je dis (et relis moi bien s'il te plaît) est qui si l'on opte pour ce design alors on aura soit le choix de caster soit le choix de copier à tour de bras …

    En très clair : c'est un mauvais design, entre autre dû cette utilisation particulière de const qui n'est pas adaptée car il y a un décalage entre ce qu'est une constante en C et la similarité du mot «constante» et du mot clé const.
    Quant à la justification «c'est un mot clé qui existe et qui dont a une utilité et donc on va l'utiliser» permet moi de te demander si tu utilises tout autant goto, auto, ou register ? Je ne pense pas (mais je peux me tromper hein).

    Ce que je dis avant tout est qu'il faut utiliser const là où c'est utile (tout comme volatile ou restrict ou goto ou dans un futur plus moins proche auto.

    Citation Envoyé par Bousk Voir le message
    Donc de ce que tu dis :

    Alourdit le code
    mais

    est totalement ok
    Et assigner à un pointeur un truc à partir d'un define, ou d'une copie retournée par une fonction, donc temporaire, est au mieux cavalier.
    À nouveau, remets tout ça dans le contexte que tu as créé : tu me demandes comment on fait, je te montre comment on fait. Il ne faut y voir «une bonne pratique que je recommanderai», bien au contraire. Que ce soit l'utilisation de const ou de #define ou d'une fonction, le design est mal foutu et ça va alourdir le code … même si c'est du C moderne.
    Je ne défends pas cette solution, ce que tu peux aisément comprendre en lisant mon message jusqu'au bout et en constatant que ce vers quoi je tendrai de but en blanc en premier jet est tout autre chose …

    Citation Envoyé par Bousk Voir le message
    Et encore une fois c'est juste ton constat de départ qui est faux parce que soit tu utilises des constantes et n'as pas à les modifier, soit tu les utilises pour créer des copies et tu en fais ce que tu veux.
    Si tu utilises les constantes, tu peux les partager et utiliser les pointeurs pour ça, mais si tu comptes en faire des copies, c'est l'utilisation de pointeurs qui devrait être remis en cause.


    T'es sûr que tu es toujours en C ?
    Parce que libérer un pointeur, ça rend juste totalement invalide l'objet pointé, ce qui est une modification assez conséquente dudit objet.
    lol bien sûr … il suffit de comprendre ce que const signifie quand il qualifie un paramètre … et ce qu'est une libération de mémoire.
    Est-ce que le fait de libérer la mémoire modifie ce qui est pointé ? non.
    Est-ce que je peux qualifier de const quelque chose qui ne sera pas modifié ? oui, c'est meme le but d'être const correct ; mais tu m'arrêteras sur ce point si je me trompe.
    Est-ce que je devrais faire taire un warning dans ce cas ? oui, car free n'est pas const correct ; tout comme une floppée d'autres fonctions standards (je citai strcpy un peu plus haut mais il y en a d'autres …)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème avec mes constantes
    Par salseropom dans le forum C
    Réponses: 6
    Dernier message: 10/05/2006, 17h37
  2. Définition multiple
    Par Goundy dans le forum C
    Réponses: 7
    Dernier message: 02/04/2006, 18h59
  3. définition multiple
    Par elekis dans le forum C++
    Réponses: 3
    Dernier message: 01/03/2006, 16h32
  4. [g++] Définitions multiples
    Par GLDavid dans le forum Autres éditeurs
    Réponses: 4
    Dernier message: 12/12/2005, 16h04
  5. Réponses: 22
    Dernier message: 05/07/2005, 00h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo