Explication sur les #import et la déclaration de constante

GreensourceGreensource Membre
06:47 modifié dans API AppKit #1
Bonjour! Il y a un point que je ne n'arrive pas à  saisir avec Objective-C.
Si par exemple j'ai trois classes: Kit,A et B.
Dans Kit:
je déclare une constante: const NSUInterger kMaConstante = 0;

Dans A:
J'importe Kit: #import "Kit.h";

Dans B:
J'importe A: #import "A.h";

Et là  sur un code de ce genre Xcode me dit que j'ai une définition multiple de kMaConstante?

Du coup la seule raison que j'ai pu voir c'est que l'import réécrivaient tout à  chaque fois! Mais je trouve pas ça logique du tout, donc en gros je comprend rien  :)

Réponses

  • CéroceCéroce Membre, Modérateur
    avril 2009 modifié #2
    En C traditionnel, inclure des fichiers ce fait par la directive de compilation #include:

    #include <stdio.h>
    


    Quand j'écris "inclure" cela signifie que le compilateur fait comme si le fichier .h était intégré dans le fichier qui l'inclus.

    Le problème d'include, c'est que si un fichier est déjà  inclus, tu risques de te retrouver avec des symboles définis plusieurs fois. Habituellement, ceci se règle de la façon suivante:

    #ifndef STDIO_H<br />#define STDIO_H<br />/* les déclarations */<br />#endif
    


    Comme c'est ennuyeux, ObjC comprend la directive de compilation #import. Elle est équivalente à  #include, sauf que le compilateur vérifie si le fichier n'a pas déjà  été inclus.
    Du coup, ton exemple est mauvais.


    Il n'est pas normal de déclarer const NSUInterger kMaConstante = 0; dans un .h.
    Un .h sert à  fournir une "interface" aux autres fichiers sources.
    Ce qui est normal est d'avoir:

    Dans Kit.h:
    extern const NSUInterger kMaConstante;

    Dans Kit.m:
    const NSUInterger kMaConstante = 0;
  • GreensourceGreensource Membre
    06:47 modifié #3
    Ah ok, merci pour ces explications! Je ne connaissait pas le mot clé extern en Obj-C.
  • AliGatorAliGator Membre, Modérateur
    06:47 modifié #4
    Pour info le mot clé "extern" :

    1) C'est du C et pas spécialement de l'Obj-C. Si tu as à  programmer en C, tu peux utiliser la même méthode qu'expliquée par Céroce donc pour le même but.

    2) Ce mot clé tel qu'utilisé ici déclare que ta constante pourra être accessible depuis d'autres fichiers C de ton projet, et pas que le fichier C qui la déclare et la définit. Si tu veux limiter sa portée au fichier C (ou Obj-C) courant, le mot clé "extern" n'est pas nécessaire.
  • mpergandmpergand Membre
    06:47 modifié #5
    Salut à  tous,

    En fait le mot extern en C n'est pas nécessaire, une déclaration du type const int kMaConst; est considérée comme extern.

    En fait le plus simple dans ce cas est d'utiliser enum:
    <br />enum<br />{<br />&nbsp; kMaConstante1,&nbsp; &nbsp; // =0<br />&nbsp; kMaConstante2,&nbsp; &nbsp; // =1<br />&nbsp; kMaConstante3=5,&nbsp; // =5<br />&nbsp; kMaConstante4&nbsp; &nbsp;  // =6<br />};
    
  • Philippe49Philippe49 Membre
    06:47 modifié #6
    C'est pas clair vos histoires sur extern.

    Dans un fichierA déclarant la variable, on ne met pas le qualifier extern, que la variable soit déclarée avec const ou non.
    // dans fichierA, fichier &quot;constructeur&quot; des variables<br />NSString * kModeA=@&quot;Mode A&quot;;<br />NSInteger globalValue;
    


    Par contre si dans d'autres fichiers  fichierB, fichierC, .. on veut avoir accès à  cette variable, on fait une déclaration qui "promet" que la variable existe à  l'exécution même si elle n'est pas présente dans ces fichiers.
    // dans fichierB, fichierC, .. les fichiers &quot;utilisateurs&quot; des variables définies dans le fichierA&nbsp; <br />extern NSString * kModeA;<br />extern NSInteger globalValue;
    
  • mouvicielmouviciel Membre
    06:47 modifié #7
    dans 1240174856:

    C'est pas clair vos histoires sur extern.


    J'essaye une nouvelle explication.

    Pour reprendre l'exemple de Philippe, j'ai trois fichiers, l'un qui déclare une constante, les deux autres qui l'utilisent (je prends l'extension .c mais je pourrais faire pareil avec .m):

    ficA.c:
    [tt]const int val = 5;[/tt]

    ficB.c:
    [tt]extern const int val;[/tt]

    ficC.c:
    [tt]extern const int val;[/tt]

    Mais c'est plus propre d'organiser les fichiers de la façon suivante:

    ficA.h:
    [tt]extern const int val;[/tt]

    ficA.c:
    [tt]const int val = 5;[/tt]

    ficB.c
    [tt]#import "ficA.h"[/tt]

    ficC.c
    [tt]#import "ficA.h"[/tt]
  • Philippe49Philippe49 Membre
    06:47 modifié #8
    dans 1240222203:


    Pour reprendre l'exemple de Philippe, j'ai trois fichiers, l'un qui déclare une constante, les deux autres qui l'utilisent (je prends l'extension .c mais je pourrais faire pareil avec .m):

    ficA.c:
    [tt]const int val = 5;[/tt]

    ficB.c:
    [tt]extern const int val;[/tt]

    ficC.c:
    [tt]extern const int val;[/tt]

    Mais c'est plus propre d'organiser les fichiers de la façon suivante:

    ficA.h:
    [tt]extern const int val;[/tt]

    ficA.c:
    [tt]const int val = 5;[/tt]

    ficB.c
    [tt]#import "ficA.h"[/tt]

    ficC.c
    [tt]#import "ficA.h"[/tt]



    Entièrement d'accord sur la définition dans les .m ou .c et non dans les .h

    Pour le reste, je ne dirais pas que c'est plus propre : Faire #import "ficA.h" réalise  l'écriture de extern const int val; dans les fichiers ficB.c et ficC.c et en plus recopie la totalité de "ficA.h"
    Donc si on veut inclure la totalité du ficA.h il faut procéder comme tu l'indiques, si par contre seule la variable val a un intérêt pour ficB/ficC, on ne voit pas la nécessité d'inclure le fichier tout entier (bien que c'est peut-être chipoter ici, le compilateur ne faisant peut-être aucune copie physique ... )
    Cette seconde option, je la rencontre assez souvent quand il s'agit non de variables mais de fonctions utilitaires codées en C.
        extern NSImage * thumbnail(NSImage* image, NSSize newSize);
        extern void translateRect(NSRectPointer rectPtr,NSSize vector);
Connectez-vous ou Inscrivez-vous pour répondre.