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

C Discussion :

Non-Lvalue Arrays May Have Subscripts


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut Non-Lvalue Arrays May Have Subscripts
    Bonjour,


    Tout d'abord je tiens à m'excuser par avance si la question a déjà été posée. J'ai cherché sur le forum avec quelques mots clés qui me sont passés par la tête mais je n'ai pas trouvé de réponse. Désolé si j'ai mal cherché...

    Dans le manuel de gcc 4.3.2, il est fait mention de "non-lvalue arrays". Je ne me suis pas mis au C99, mais il me semble que l'expression ne figure pas dans le standard. En tout cas, dans le K&R2, si j'ai bonne mémoire, il y a une ligne qui dit quelque chose du genre: "Arrays are not lvalues." Donc, je trouve l'expression utilisée dans le manuel de gcc vraiment bizarre...

    Ce que je ne saisis pas trop bien non plus, c'est le paragraphe "5.19 Non-Lvalue Arrays May Have Subscripts". Je ne vois pas pourquoi le code présenté - dans le manuel de gcc - n'est pas valide en C89.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct foo {int a[4];};
    struct foo f();
     
    bar (int index)
    {
        return f().a[index];
    }
    J'ai testé sous Borland 5.5 et ça compile correctement. Je suis conscient que cela ne signifie pas que c'est conforme à la norme, ce pourrait être une extension du compilateur ou bien juste une non conformité à la norme.

    Vos explications sont les bienvenues. Merci d'avance,
    Stephane

  2. #2
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    117
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Mars 2006
    Messages : 117
    Par défaut
    Hello,

    je ne comprend pas trop ce que tu veux faire en faisant :
    En C il n'y a pas de notion de classe et donc de constructeur comme dans les langages plus haut niveau.

    à mon avis ce que tu as voulut ecrire est plutot :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct foo {int a[4];};
    struct foo f;
     
    int bar (int index)
    {
        return f.a[index];
    }
    De plus tu devrais compiler avec les flags -Wall -Werror aussi car tu n'avais pas de type de retour sur ta fonction, ce qui n'est pas dramatique mais n'est pas tres propre ni tres secure au niveau du type checking.

    J'espere avoir bien compris ce que tu voulais faire.

    A bientot,

    Oniric.

  3. #3
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Merci pour tes réponses. Le code est extrait du manuel de gcc. Pour le test que j'ai effectué, voici le code que j'ai utilisé:
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <stdio.h>
     
     
    struct foo {int a[4];};
     
     
    struct foo f(void)
    {
    	struct foo st = {8 ,9 ,10 ,11};
    	return st;
    }
     
     
    int bar(int index)
    {
    	return f().a[index];
    }
     
     
    int main(void)
    {
    	printf("%d\n", bar(1));
    	return 0;
    }
    Je sais bien qu'il n'y a pas de classe en C, et je ne cherche pas à en émuler. Je veux juste comprendre ce paragraphe du manuel de gcc.

  4. #4
    Membre confirmé
    Inscrit en
    Mars 2006
    Messages
    117
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Mars 2006
    Messages : 117
    Par défaut
    J'ai compris ce dont tu parlais, je ne comprenais pas tout à l'heure.

    Je ne peux actuellement pas lire le man de gcc (je suis sous windows deja ... et j'ai un acces limité au net). Mais j'ai compris ce que tu voulais faire et je pense "deviner" pourquoi ce code ne fonctionne pas en C89.

    Le probleme se situe surement au niveau du type checking, c'est à dire le moment ou le compilateur verifie les types des variables et leurs compatibilités mutuelles.
    En C89 le type checking devait etre moins poussé et lorsque tu fais
    il voudrai que f() soit un type "struct" (à cause de l'operateur '.') hors, c'est une fonction. Il ne va pas chercher à regarder le retour de la fonction, ce que fait surement le C99.
    Cette ecriture necessite que le compilateur désucre la ligne en faisant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int bar(int index)
    {
    struct foo tmp = f();
     
    	return tmp.a[index];
    }
    Le C89 ne doit pas savoir desucré la ligne du coup il ne peut pas faire le bind entre l'adresse de retour de f() et a[index].

    Si tu cherches à comprendre comment fonctionne les compilateurs, je te conseil de regarder ce genre de livre : http://www.cs.princeton.edu/~appel/modern/c/

    J'ai bcp appris et compris à l'epoque grace à ca (il y a un moment, donc mes explications ne sont peut etre pas tres clair, ni à prendre pour parole d'evangile ! )

    nb : sucrage syntaxique : fait de donner au programmeur des possibilités d'écriture plus succinctes ou plus proches d'une notation usuelle.
    exemple en C89 : tableau[i] est en faite un sucre syntaxique traduit à la pré compilation par : *(tableau + i)

  5. #5
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Citation Envoyé par oniric Voir le message
    Mais j'ai compris ce que tu voulais faire [...]
    Juste pour être sûr: je ne veux rien faire du tout, sinon comprendre pourquoi le manuel de gcc cite ce code comme invalide en C89.
    Citation Envoyé par oniric Voir le message
    En C89 le type checking devait etre moins poussé [...]
    Pourquoi pas, mais cela me semble bizarre.
    Citation Envoyé par oniric Voir le message
    il voudrai que f() soit un type "struct" (à cause de l'operateur '.') hors, c'est une fonction. Il ne va pas chercher à regarder le retour de la fonction, ce que fait surement le C99.
    Je ne suis pas sûr que ce soit l'explication car d'après le manuel de gcc, il semble que le problème ne soit pas lié au fait que l'on accède à un membre de la structure mais au fait que l'on indexe ce membre qui est un tableau.

    En tout cas, merci pour tes réponses et ton lien vers le livre.

  6. #6
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    la norme C89 dit:
    3.2.2.1 Lvalues and function designators

    An lvalue is an expression (with an object type or an incomplete type other than void) that designates an object.24 When an object is said to have a particular type, the type is specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member of all contained structures or unions) with a const-qualified type.

    Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue). If the lvalue has qualified type, the value has the unqualified version of the type of the lvalue; otherwise the value has the type of the lvalue. If the lvalue has an incomplete type and does not have array type, the behavior is undefined.

    Except when it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type compatible with wchar_t, an lvalue that has type ``array of type '' is converted to an expression that has type ``pointer to type '' that points to the initial member of the array object and is not an lvalue.
    la norme C99 dit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    5 This second edition cancels and replaces the first edition, ISO/IEC 9899:1990, as
      amended and corrected by ISO/IEC 9899/COR1:1994, ISO/IEC 9899/AMD1:1995, and
      ISO/IEC 9899/COR2:1996. Major changes from the previous edition include:
    ...
    — conversion of array to pointer not limited to lvalues
    et
    6.3.2.1 Lvalues, arrays, and function designators
    An lvalue is an expression with an object type or an incomplete type other than void;53)
    1
    if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
    When an object is said to have a particular type, the type is specified by the lvalue used to
    designate the object. A modifiable lvalue is an lvalue that does not have array type, does
    not have an incomplete type, does not have a const-qualified type, and if it is a structure
    or union, does not have any member (including, recursively, any member or element of
    all contained aggregates or unions) with a const-qualified type.
    2 Except when it is the operand of the sizeof operator, the unary & operator, the ++
    operator, the -- operator, or the left operand of the . operator or an assignment operator,
    an lvalue that does not have array type is converted to the value stored in the designated
    object (and is no longer an lvalue). If the lvalue has qualified type, the value has the
    unqualified version of the type of the lvalue; otherwise, the value has the type of the
    lvalue. If the lvalue has an incomplete type and does not have array type, the behavior is
    undefined.
    3 Except when it is the operand of the sizeof operator or the unary & operator, or is a
    string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
    converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
    the array object and is not an lvalue.
    If the array object has register storage class, the
    behavior is undefined.
    étant donné qu'une fonction retourne une rvalue, l'instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct foo {int a[4];};
    struct foo f();
     
    bar (int index)
    {
        return f().a[index];
    }
    est incorrect en C89 mais pas en C99.

  7. #7
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par stephl Voir le message
    Ce que je ne saisis pas trop bien non plus, c'est le paragraphe "5.19 Non-Lvalue Arrays May Have Subscripts". Je ne vois pas pourquoi le code présenté - dans le manuel de gcc - n'est pas valide en C89.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct foo {int a[4];};
    struct foo f();
     
    bar (int index)
    {
        return f().a[index];
    }
    J'ai testé sous Borland 5.5 et ça compile correctement. Je suis conscient que cela ne signifie pas que c'est conforme à la norme, ce pourrait être une extension du compilateur ou bien juste une non conformité à la norme.
    ceci fonctionne avec MinGW en mode C90 :
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    #include <stdio.h>
     
    struct foo
    {
       int a[4];
    };
     
    struct foo f ()
    {
       struct foo foo = { {10, 11, 12, 13} };
       return foo;
    }
     
    int bar (int index)
    {
       int x = f ().a[index];
       return x;
    }
     
    int main (void)
    {
       int y = bar (2);
     
       printf ("y = %d\n", y);
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    y = 12
     
    Process returned 0 (0x0)   execution time : 0.069 s
    Press any key to continue.
    Certes, il y a un warning, mais je ne suis pas certain qu'il soit justifié...

    En fait, si. Voir l'explication de Nicolas.

    J'avoue que ces subtilités me donnent mal à la tête, surtout que comme toi, j'avais déjà utilisé de genre de codage un peu ... extrême, sous Borland C++, sans warning... (mais je n'étais peut être pas en mode ANSI strict : ligne de commande : -A ).

  8. #8
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    [...] Certes, il y a un warning, mais je ne suis pas certain qu'il soit justifié...
    En fait, si. Voir l'explication de Nicolas.
    Oui, le warning apparaît quand on ajoute pedantic.

    Citation Envoyé par Emmanuel Delahaye Voir le message
    J'avoue que ces subtilités me donnent mal à la tête [...]
    Ah, bon je ne suis pas le seul alors .

  9. #9
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Bizarre :
    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
    16
    17
    18
    19
    20
    struct foo
     {
      int a[4];
      int b;
     };
     
    struct foo f(void)
    {
      struct foo st = {{8 ,9 ,10 ,11},-1};	
      return st;
    }
    int main(void)
    {
     // Ce qui m'inquiète est plutôt que ceci soit toléré (même si ça ne fait rien) :
       f().a[1] = 5;
     
     //  Alors que bien sûr, ceci ne l'est pas (ce qui est compréhensible) : invalid lvalue
     //  f().b = 5;
       return 0;
    }
    Remarque :

    n1256 :
    6.5.2.1 Array subscripting
    ...
    2 A postfix expression followed by an expression in square brackets [] is a subscripted
    designation of an element of an array object. The definition of the subscript operator []
    is that E1[E2] is identical to (*((E1)+(E2)))...
    Si, X[i] est considéré équivalent à *(X+i), on aboutit à :

    f().a[1] <-> *(f().a +1)

    La première écriture est admise et pas la seconde
    Conclusion : un interprétation particulière est faite pour l'opérateur [] si il s'agit d'un tableau qui n'est pas une lvalue !

  10. #10
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par diogene Voir le message
    Bizarre :
    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
    16
    17
    18
    19
    20
    struct foo
     {
      int a[4];
      int b;
     };
     
    struct foo f(void)
    {
      struct foo st = {{8 ,9 ,10 ,11},-1};	
      return st;
    }
    int main(void)
    {
     // Ce qui m'inquiète est plutôt que ceci soit toléré (même si ça ne fait rien) :
       f().a[1] = 5;
     
     //  Alors que bien sûr, ceci ne l'est pas (ce qui est compréhensible) : invalid lvalue
     //  f().b = 5;
       return 0;
    }
    Remarque :

    n1256 :


    Si, X[i] est considéré équivalent à *(X+i), on aboutit à :

    f().a[1] <-> *(f().a +1)

    La première écriture est admise et pas la seconde
    Conclusion : un interprétation particulière est faite pour l'opérateur [] si il s'agit d'un tableau qui n'est pas une lvalue !
    Aucune des 2 n'est permises!
    "main.c", line 15: warning: left operand of "." must be lvalue in this context, program behavior is undefined
    "main.c", line 18: warning: left operand of "." must be lvalue in this context, program behavior is undefined

  11. #11
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Je préfère ça qui est logique. Mais aucun avertissement n'était émis par mingw pour la forme f().a[1] = 5; et une erreur était signalée pour la seconde f().b = 5;

    Accessoirement, un warning me semble insuffisant.

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

Discussions similaires

  1. [Débutant] Attempt to reference field of non-structure array.
    Par ptichum dans le forum Interfaces Graphiques
    Réponses: 4
    Dernier message: 06/01/2010, 22h20
  2. Attempt to reference field of non-structure array.
    Par gmachi10 dans le forum Interfaces Graphiques
    Réponses: 2
    Dernier message: 26/06/2009, 09h01
  3. erreur :Cell contents assignment to a non-cell array object.
    Par lince102 dans le forum Interfaces Graphiques
    Réponses: 5
    Dernier message: 17/12/2007, 15h09
  4. [Débutant] boost::thread non-lvalue
    Par Tymk dans le forum Boost
    Réponses: 16
    Dernier message: 18/11/2006, 14h23
  5. Réponses: 5
    Dernier message: 20/10/2006, 14h31

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