objective-C, C'est du C?

tabliertablier Membre
20:36 modifié dans API AppKit #1
Objective-C, c'est du C! J'ai donc écrit le code ci-dessous:

#import &lt;Cocoa/Cocoa.h&gt;<br /><br /><br />@interface leControl : NSObject<br />{<br />&nbsp; &nbsp; IBOutlet NSWindow *o_fenetre;<br />&nbsp; &nbsp; IBOutlet NSMatrix *o_radio;<br />&nbsp; &nbsp; IBOutlet NSButton *o_swich1;<br />&nbsp; &nbsp; IBOutlet NSButton *o_switch2;<br />&nbsp; &nbsp; IBOutlet NSTextField *o_texte;<br /><br />	struct le_champ {<br />		char&nbsp; *lenom ;<br />		int	letype ;<br />		} DVDchamps[4] = { {&quot;zero&quot;, 0},&nbsp; {&quot;un&quot;, 1},&nbsp; {&quot;deux&quot;, 2},&nbsp; {&quot;trois&quot;, 3} }&nbsp; ;<br />}<br />- (IBAction)a_annule:(id)sender;<br />- (IBAction)a_ok:(id)sender;<br />@end<br />


Ce code sort presque directement du "Kernigham et richie". j'obtiens systématiquement l'erreur: "error: parse error before '=' token"
quelqu'un aurait une explication?
«1

Réponses

  • TchouboudouTchouboudou Membre
    20:36 modifié #2
    Il me semble, mais je ne suis pas sûr, que le C dans le .h, ça marche pas dans @interface (comme tu as pu le remarquer), il faut le faire en dehors. Mais tu dois le savoir aussi...

  • tabliertablier Membre
    20:36 modifié #3
    eh bien non je ne sais pas ça! Note que je ne suis pas informaticien du tout! je fait du C depuis longtemps, et de l'objective C depuis 3 ans. Je n'ai jamais rien lu sur ce type de non fonctionnement!
    Je vais essayer autrement. Si non, ou puis-je lire des infos sur ce genre de difficultés?
  • TchouboudouTchouboudou Membre
    20:36 modifié #4
    En fait, je sais ça juste en regardant le code des exemples Apple (en cherchant à  faire des raccourcis claviers). Je pourrais pas vraiment t'indiquer où trouver ces renseignements, je ne fais de l'Obj-C que depuis 1 an :D . Mais il me semble qu'il y a un tutoriel sur developpez qui parle du passage du C++ à  l'Objective-C. Il pourrait y avoir des renseignements là -dessus.

    En tout cas, bonne chance ;)
  • LeChatNoirLeChatNoir Membre, Modérateur
    20:36 modifié #5
    Hello,
    Je confirme, ça fonctionne (en dehors de @interface/@end)

    A+

  • psychoh13psychoh13 Mothership Developer Membre
    novembre 2007 modifié #6
    dans 1195844617:

    Objective-C, c'est du C!


    Justement, c'est du C, c'est d'ailleurs pour ça que ce que tu as écrit ne fonctionne pas. Si tu testes en C pur (même C99) tu auras cette erreur. Pourquoi ?

    Tout simplement parce que lorsque tu définis une structure en C, elle n'a pas d'existence dans la mémoire, on ne peut donc pas affecter des valeurs à  ses champs lors de la déclaration. Essaye ceci en C :

    struct test {<br />	struct le_champ {<br />		char&nbsp; *lenom ;<br />		int	letype ;<br />	} DVDchamps[4] = { {&quot;zero&quot;, 0},&nbsp; {&quot;un&quot;, 1},&nbsp; {&quot;deux&quot;, 2},&nbsp; {&quot;trois&quot;, 3} };<br />};
    


    Mon compilateur me renvoie une erreur similaire : error: syntax error before ‘=' token

    En revanche, si tu écris :
    struct le_champ {<br />	char&nbsp; *lenom ;<br />	int	letype ;<br />} DVDchamps[4] = { {&quot;zero&quot;, 0},&nbsp; {&quot;un&quot;, 1},&nbsp; {&quot;deux&quot;, 2},&nbsp; {&quot;trois&quot;, 3} };
    


    C'est qu'en fait tu fais deux choses à  la fois, tu fais d'abord la déclaration :

    struct le_champ {<br />	char&nbsp; *lenom ;<br />	int	letype ;<br />};
    


    Suivit de la création d'une nouvelle variable :

    struct le_champ = DVDchamps[4] = { {&quot;zero&quot;, 0},&nbsp; {&quot;un&quot;, 1},&nbsp; {&quot;deux&quot;, 2},&nbsp; {&quot;trois&quot;, 3} };
    


    Il est en revanche tout à  fait possible dans les variables d'instance d'une classe de définir, comme en C dans une structure, de nouvelles structures et de donner un nom de champ :

    #import &lt;Cocoa/Cocoa.h&gt;<br /><br /><br />@interface leControl : NSObject<br />{<br />&nbsp; &nbsp; IBOutlet NSWindow *o_fenetre;<br />&nbsp; &nbsp; IBOutlet NSMatrix *o_radio;<br />&nbsp; &nbsp; IBOutlet NSButton *o_swich1;<br />&nbsp; &nbsp; IBOutlet NSButton *o_switch2;<br />&nbsp; &nbsp; IBOutlet NSTextField *o_texte;<br /><br />	struct le_champ {<br />		char&nbsp; *lenom ;<br />		int	letype ;<br />		} DVDchamps[4];<br />}<br />- (IBAction)a_annule:(id)sender;<br />- (IBAction)a_ok:(id)sender;<br />@end
    


    Conclusion : l'erreur que tu trouves est une erreur tout à  fait normale du point de vue de l'Objective-C comme du C.
  • tabliertablier Membre
    novembre 2007 modifié #7
    A la lumière de ce qui a été répondu j'ai changé le code sans changer la déclaration:
    #import &lt;Cocoa/Cocoa.h&gt;<br /><br />struct le_champ {<br />&nbsp;  char&nbsp;  *lenom ;<br />&nbsp;  int&nbsp; &nbsp; letype ;<br />} DVDchamps[4] = { {&quot;zero&quot;, 0}, {&quot;un&quot;, 1}, {&quot;deux&quot;, 2}, {&quot;trois&quot;, 3} } ;<br /><br />@interface leControl : NSObject<br />{<br />&nbsp; IBOutlet NSWindow *o_fenetre;<br />&nbsp; IBOutlet NSMatrix *o_radio;<br />&nbsp; IBOutlet NSButton *o_swich1;<br />&nbsp; IBOutlet NSButton *o_switch2;<br />&nbsp; IBOutlet NSTextField *o_texte;<br />}<br />- (IBAction)a_annule:(id)sender;<br />- (IBAction)a_ok:(id)sender;<br />@end<br />
    

    et là , je n'ai plus d'erreur! Ce n'est pas la syntaxe qui est en cause, mais la place de la déclaration-initialisation. Plus exactement c'est l'initialisation directe entre { et } de l'@interface qui parait interdite.
    Pour vérifier, j'ai écrit:
    @interface leControl : NSObject<br />{<br />&nbsp; IBOutlet NSWindow *o_fenetre;<br />&nbsp; IBOutlet NSMatrix *o_radio;<br />&nbsp; IBOutlet NSButton *o_swich1;<br />&nbsp; IBOutlet NSButton *o_switch2;<br />&nbsp; IBOutlet NSTextField *o_texte;<br />&nbsp; int x = 34 ;<br />}<br />
    

    et l'erreur précitée réapparait!
    Merci à  tous et A+  :P
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #8
    C'est normal, tu ne peux pas faire d'affectation DANS la déclaration d'une structure en C, or les accolades dans l'@interface d'une classe représente strictement la définition d'une structure, pour être précis il s'agit d'une structure partielle, puisque le compilateur va récupérer les déclarations des structures des super-classes pour créer la structure finale de la classe.

    Mais, il s'agit d'une déclaration de structure, en C on ne peut pas faire d'affectation dans une déclaration de structure, alors dans une déclaration de classe on ne peut pas non plus le faire.
  • 20:36 modifié #9
    Je me demande pourquoi tu ne crée pas une classe toute propre ?
  • Philippe49Philippe49 Membre
    20:36 modifié #10
    dans 1195859629:

    @interface d'une classe représente strictement la définition d'une structure
    ...
    en C on ne peut pas faire d'affectation dans une déclaration de structure, alors dans une déclaration de classe on ne peut pas non plus le faire.


    Ben oui. 

    On peut par artifice provoquer un comportement analogue.
    Exemple : un compteur d'instances
    <br />static int compteur=0;<br /><br />@implementation MaClasse<br />-(id) init<br />{<br />	if(self=[super init]){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...<br />		compteur++;<br />	}<br />&nbsp; &nbsp; &nbsp;  return self;<br />}<br />-(void) dealloc<br />{<br />&nbsp; &nbsp; &nbsp;  compteur--;<br />&nbsp; &nbsp; &nbsp;  ...<br />}
    

  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #11
    Je comprends pas ce que t'essayes de prouver Philippe  ???

    De plus, rien ne t'empêches de définir ton compteur entre les directives @interface et @end de ta classe (après les accolades, puisque tu peux pas définir de variable d'instance statiques), il t'avertira que ta variable compteur n'est pas utilisé mais en fait elle le sera. Voire tu peux même les définir entre les directives @implementation et @end et en plus tu auras un warning de moins.
  • Philippe49Philippe49 Membre
    novembre 2007 modifié #12
    dans 1195902061:

    Je comprends pas ce que t'essayes de prouver Philippe  ???

    Le topic parle d'initialisation lors de la déclaration d'une classe. Cela ne peut avoir de vraie utilité que pour une variable qui serait partagée par toutes les instances, et non pas aux instances, sinon il n'y a qu'à  le faire dans -(id)init.
    Je présente ici une possibilité détournée de créer/initialiser/mettre à  jour une telle variable partagée par toutes les instances.
    En fait cette variable est une variable globale. 

    dans 1195902061:

    De plus, rien ne t'empêches de définir ton compteur entre les directives @interface et @end de ta classe (après les accolades, puisque tu peux pas définir de variable d'instance statiques), il t'avertira que ta variable compteur n'est pas utilisé mais en fait elle le sera. Voire tu peux même les définir entre les directives @implementation et @end

    Certes. la place logique est extérieure à  la zone "instance de classe".
    Dans le .h entre @interface et @end, extérieur aux accolades, cela marche, mais je ne vois pas trop la signification.
    Extérieurement cela me semble clair : c'est en quelque sorte rajoutée aux déclarations de la classe, visible par les instances.
    Dans le .h,cela devrait être visible pour les autres classes après #import.
    Dans le .m, c'est réservé aux instances.
    Ceci dit si on prend un compteur de même nom pour deux classes différentes, sans avoir essayé, je pressens un conflit.

    dans 1195902061:

    et en plus tu auras un warning de moins.

    mon code est sans warning ( sauf le if(self=[super init]), mais c'est autre chose ).

  • schlumschlum Membre
    20:36 modifié #13
    En C++ On peut avoir des variables statiques liées à  la classe... En Objective-C, je ne pense pas  ???
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #14
    dans 1195911655:

    Certes. la place logique est extérieure à  la zone "instance de classe".
    Dans le .h extérieur aux accolades, cela marche, mais je ne vois pas trop la signification.
    Extérieurement cela me semble clair : c'est en quelque sorte rajoutée aux déclarations de la classe, visible par les instances.
    Dans le .h, cela devrait être visible pour les autres classes après #import.
    Dans le .m, c'est réservé aux instances.
    Ceci dit si on prend un compteur de même nom pour deux classes différentes, sans avoir essayé, je pressens un conflit.


    J'ai fait l'essai, j'ai définit une classe dans le même fichier que le main, et une dans un fichier séparé, j'ai définit mes variables compteur comme étant static dans les .m et pas dans les .h, il n'y a aucun conflit entre elles.

    dans 1195902061:
    mon code est sans warning ( sauf le if(self=[super init]), mais c'est autre chose ).


    Je ne parlais pas du tien. Si tu définis ta variable static dans l'interface de la classe, mais que tu ne l'utilises pas dans le même fichier, il te dira que la variable n'est pas utilité (warning), en revanche si tu la définis dans l'implémentation, le warning disparaà®t.
  • schlumschlum Membre
    novembre 2007 modifié #15
    dans 1195912955:

    J'ai fait l'essai, j'ai définit une classe dans le même fichier que le main, et une dans un fichier séparé, j'ai définit mes variables compteur comme étant static dans les .m et pas dans les .h, il n'y a aucun conflit entre elles.


    Normal qu'il n'y ait pas de conflit... C'est la même  :P
    Essaie de les utiliser, t'auras des surprises  ;)

    PS : dans les .h non plus il n'y a pas de conflit...
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #16
    dans 1195914121:
    Normal qu'il n'y ait pas de conflit... C'est la même  :P
    Essaie de les utiliser, t'auras des surprises  ;)


    Non non, j'ai fait le test, les valeurs changent indépendamment.
  • schlumschlum Membre
    20:36 modifié #17
    Effectivement... Ben j'appelle ça un bug alors  :P

    Parce que là  :

    #import &quot;Class1.h&quot;<br /><br />static int cpt = 0;<br /><br />@implementation Class1<br /><br />- (id) init {<br />	self = [super init];<br />	if (self != nil) {<br />		++cpt;<br />	}<br />	return self;<br />}<br /><br />- (void) dealloc {<br />	--cpt;<br />	[super dealloc];<br />}<br /><br />+ (void) print {<br />	NSLog(@&quot;%d&quot;,cpt);<br />}<br /><br />@end
    


    "cpt" ne devrait rien avoir à  voir avec "Class1"

    C'est une variable statique qui est censée être globale partout, or là  elle tient compte du scoping, c'est pas normal.
  • schlumschlum Membre
    20:36 modifié #18
    Après un petit passage chez Kernighan et Ritchie, effectivement, "static" est limité à  la portée du fichier source.
    Donc c'est OK...

    C'est de la bidouille pas très objet ça quand même  :)
  • psychoh13psychoh13 Mothership Developer Membre
    novembre 2007 modifié #19
    Bah non, le mot clé static limite la portée d'une variable ou d'une fonction à  l'unité de compilation dans laquelle elle est définie. En l'occurrence, l'unité en question c'est le fichier .m donc la variable est réservée au fichier. static c'est pratiquement l'opposé de global.

    Quand une variable static est définie dans une fonction, elle est définie et initialisée qu'une seule fois, ensuite, lors des autres appels de la fonction, elle conserve la valeur qu'elle avait à  la fin du précédent appel.
    Lorsque la variable est définie dans un fichier qui n'est inclut nul par ailleurs, la variable en question est réservée au fichier dans lequel elle est définie.

    dans 1195915365:

    Après un petit passage chez Kernighan et Ritchie, effectivement, "static" est limité à  la portée du fichier source.
    Donc c'est OK...

    C'est de la bidouille pas très objet ça quand même  :)


    Bah c'est-à -dire que les créateurs de l'Objective-C n'ont pas prévu de variable de classe tout simplement parce que le C avait déjà  ce mécanisme, pa sla peine de le redéfinir, c'est vrai que c'est pas très propre, mais bon, pourquoi réinventer la roue ? :D

    À mon avis ce système était plus simple à  mettre en place que des variables de classe qui aurait obligé à  créer des structures différentes pour chaque classe, alors que là  on ne fait varier que les données que la structure de classe contient.
  • schlumschlum Membre
    20:36 modifié #20
    Ce qui est surtout pas propre, c'est de devoir le définir dans le .m
  • schlumschlum Membre
    20:36 modifié #21
    dans 1195915675:

    À mon avis ce système était plus simple à  mettre en place que des variables de classe qui aurait obligé à  créer des structures différentes pour chaque classe, alors que là  on ne fait varier que les données que la structure de classe contient.


    C'est un faux problème... Ils ont bien fait des méthodes de classe  :P
    Il n'y a pas énormément de différence entre les deux... C'est juste un pointeur à  ajouter dans les structures.
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #22
    dans 1195916337:
    C'est un faux problème... Ils ont bien fait des méthodes de classe  :P
    Il n'y a pas énormément de différence entre les deux... C'est juste un pointeur à  ajouter dans les structures.


    Bah non justement, il n'est pas si faux que ça le problème. Les classes sont des structures prédéfinies dont voici l'ancienne apparence :

    struct objc_class {			<br />	struct objc_class *isa;	<br />	struct objc_class *super_class;	<br />	const char *name;		<br />	long version;<br />	long info;<br />	long instance_size;<br />	struct objc_ivar_list *ivars;<br /><br />	struct objc_method_list **methodLists;<br /><br />	struct objc_cache *cache;<br /> 	struct objc_protocol_list *protocols;<br />};
    


    Le compilateur va simplement concevoir des instances de cette structures et en remplissant chaque champ avec les valeurs qu'il faut, c'est-à -dire la liste des variables d'instance (leur nom, leur type et leur place dans la structure), la liste des méthodes (sélecteur, types, adresse), et la liste des protocoles...
    Je suis pas sûr que ça soit si facile d'ajouter des variables de classe... Quoique... à‰ventuellement, on pourrait ajouter un champ à  cette structure contenant les adresses des variables de classe et leur type... Mais bon, encore faut-il y arriver.
  • Philippe49Philippe49 Membre
    20:36 modifié #23
    dans 1195915675:

    Bah non, le mot clé static limite la portée d'une variable ou d'une fonction à  l'unité de compilation dans laquelle elle est définie. En l'occurrence, l'unité en question c'est le fichier .m donc la variable est réservée au fichier. static c'est pratiquement l'opposé de global.

    Quand une variable static est définie dans une fonction, elle est définie et initialisée qu'une seule fois, ensuite, lors des autres appels de la fonction, elle conserve la valeur qu'elle avait à  la fin du précédent appel.
    Lorsque la variable est définie dans un fichier qui n'est inclut nul par ailleurs, la variable en question est réservée au fichier dans lequel elle est définie.


    Une variable statique a un comportement semblable à  une variable globale au niveau de la durée de vie de l'information qu'elle porte.
    Par contre au niveau de la visibilité, elle se comporte comme une variable automatique.
    Dans le cas d'un source unique, et d'une définition comme on la dispose, c'est une variable globale.

    dans 1195915675:

    J'ai fait l'essai, j'ai définit une classe dans le même fichier que le main, et une dans un fichier séparé, j'ai définit mes variables compteur comme étant static dans les .m et pas dans les .h, il n'y a aucun conflit entre elles

    c'est au niveau de la compilation que je craignais un conflit : genre "redéfinition d'une variable déjà  existante". Mais en cas de compilation séparée, cela résout effectivement le problème.

  • schlumschlum Membre
    novembre 2007 modifié #24
    Une variable de classe c'est la même chose qu'une variable d'instance sauf que c'est un pointeur sur une variable (initialisée avant toute instantiation), commun à  toutes les instances...

    D'ailleurs, les méthodes sont du même genre... C'est le même pointeur pour toutes les instances. (en C++ tout du moins, parce qu'en Objective-C, c'est un peu spécial)
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #25
    dans 1195917661:

    Une variable de classe c'est la même chose qu'une variable d'instance sauf que c'est un pointeur sur une variable (initialisée avant toute instantiation), commun à  toutes les instances...


    En quel langage c'est un pointeur sur une variable ? Parce que jusqu'à  nouvel ordre, ça n'existe pas en Objective-C. D'ailleurs je doute fortement que ce soit définit comme ça en C++ par exemple, ça utiliserait de la mémoire en plus pour stocker la valeur du pointeur de la variable de classe, ce n'est pas très économique, surtout pour pointé sur un unique élément bien définit. Et comme en C++, tout se passe à  la compilation, le compilateur peut aisément retrouver la variable dans la mémoire.

    dans 1195917661:
    D'ailleurs, les méthodes sont du même genre... C'est le même pointeur pour toutes les instances. (en C++ tout du moins, parce qu'en Objective-C, c'est un peu spécial)


    En Objective-C, tous les objets ont dans leur variables d'instance un pointeur sur la structure représentant leur classe, et tous les pointeurs sur les méthodes sont stockés dans cette structure et cela permet de laisser au runtime le loisir de choisir la méthode à  exécuter.

    En C++, tout est définit à  la compilation, donc à  priori il n'y a pas besoin de stocker les pointeurs sur les méthodes, cela fonction comme les fonctions en C, le nom indique directement le code à  exécuter. Il n'y a que pour les méthodes "virtual" qui fonctionnent différemment...
  • schlumschlum Membre
    novembre 2007 modifié #26
    Non, c'est pas stocké dans la structure (heureusement)... C'était une image pour dire qu'implémenter les variables de classe c'est pas plus dur qu'implémenter les méthodes.

    Quant à  "virtual", ce n'est qu'une indication au compilateur pour dire que la méthode doit être implémentée dans les classes filles...
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #27
    dans 1195922684:

    Non, c'est pas stocké dans la structure (heureusement)... C'était une image pour dire qu'implémenter les variables de classe c'est pas plus dur qu'implémenter les méthodes.

    Quand à  "virtual", ce n'est qu'une indication au compilateur pour dire que la méthode doit être implémentée dans les classes filles...

    Quant*

    Non, "virtual" indique que la méthode PEUT être redéfinie dans les sous-classes, et que donc il doit laisser le choix du code à  exécuter à  l'exécution. C'est lorsque la méthode est virtuelle pure qu'elle DOIT être redéfinie par les classes filles.

    Sinon je suis pas vraiment d'accord sur le fait que ce ne soit pas plus dur d'implémenter une variable de classe que d'implémenter les méthodes de classe...
  • schlumschlum Membre
    20:36 modifié #28
    Certes (je n'utilise pas les virtuelles non pures... Quand on commence à  avoir besoin de ça, c'est qu'on a vraiment un code qui part dans tous les sens  :P)... Mais c'est quand même une indication pour le compilateur ; rien ne change quant (* ;) ) au stockage de ces fonctions en interne.

    Pour les variables de classe, je ne pense pas que c'est pour la difficulté qu'ils ne l'ont pas mis, ou juste parce qu'il y avait déjà  une méthode moins propre avec les static dans le .m...
    C'est juste que c'est un concept pas très "objet", et qui ne sert que dans des cas très marginaux.
    Le programmeur ne devrait pas avoir à  "compter ses instances" dans un autre but que du debugging.
  • AliGatorAliGator Membre, Modérateur
    20:36 modifié #29
    Heu, j'avoue ne pas avoir eu le courage de tout lire sur vos derniers messages, mais je capte pas trop le problème :
    Quand on veut faire une variable de classe en C++ on utilise bien le mot clé "static", d'ailleurs il est fait pour ça :P
    Et, de même, en C++, on déclare la variable de classe en "static" dans le ".h", et on l'initialise dans le ".cpp", d'ailleurs hors du code de la classe, comme on initialise une variable globale.

    Alors en quoi ça vous pose souci ici ? Parce que c'est une static "de fichier" et pas "au sein d'une fonction ou d'une classe" ? Ben oui mais en même temps on est en C (enfin Obj-C) donc les classes de base ça n'existe pas en C... Alors c'est normal qu'on retombe dans ce mécanisme, non ?

    Bon ok la déclaration du "static" pourrait être dans un @interface, mais l'initialisation dans le .m et hors du @implementation c'est comme en C++, non ?
    Du coup ça suit la syntaxe du C tout en gardant les principes de codages du C++ (côté objet apporté par l'Objective-C)
  • psychoh13psychoh13 Mothership Developer Membre
    20:36 modifié #30
    Bah, faire la déclaration et l'initialisation dans le @implementation c'est plutôt la formule à  préférer. Mais c'est juste qu'il trouve ça moche parce que les variables ne sont pas clairement gérés par la classe et que c'est un peu un mécanisme détourné.
  • schlumschlum Membre
    20:36 modifié #31
    dans 1195939642:

    Bon ok la déclaration du "static" pourrait être dans un @interface, mais l'initialisation dans le .m et hors du @implementation c'est comme en C++, non ?
    Du coup ça suit la syntaxe du C tout en gardant les principes de codages du C++ (côté objet apporté par l'Objective-C)


    Non, le problème c'est qu'il faut faire la déclaration dans le .m aussi !

    Alors qu'en C++ on le fait dans le .h, c'est quand même plus logique...
Connectez-vous ou Inscrivez-vous pour répondre.