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 :

Différence entre [] et *


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2016
    Messages : 10
    Par défaut Différence entre [] et *
    Bonjour à tous et tout d'abord bonne et heureuse année 2017.

    Je suis confronté à un petit problème de compréhension.

    J'ai acheté le livre 'Le guide complet du langage C' aux éditions Eyrolles et dans ce livre il est écrit au chapitre 6.1 page 290 ceci :

    On peut déclarer un prototype de fonctions comme suit et ils seront équivalents avec des tableaux en arguments muets:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void function( int * t );
     
    void function( int t[10] );
     
    void function( int t[] );

    et cela fonctionne très bien en C sous Visual Studio, ou Keil.

    Maintenant si je considère qu'une structure peut avoir une représentation sous la forme d'un tableau, je peux éventuellement écrire ce qui suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    /** Déclaration anticipée **/
    struct enreg;
    typedef struct enreg Ts_enreg;
     
    /** Prototypes **/
    void function_ptr( Ts_enreg * objects);    //---> compilateur dit OK !
    void function_array( Ts_enreg objects[]); //---> compilateur dit KO car enreg n'est pas encore défini !!
    On dirait que le compilo (qui n'est pas visual) fait la distinction entre * et [].
    J'ai contacté le support technique et la réponse est la suivante :
    Si votre manuel prétend que cela est censé fonctionner, vous avez besoin d'un autre, parce que celui que vous avez n'est pas réellement sur le langage de programmation C.

    "Les prototypes MyFunc_1 et MyFunc_2 sont équivalents"

    Non, ils ne sont pas. C'est une chose de déclarer une fonction qui prend un type inconnu, mais tout à fait différent si elle prend un pointeur vers ce type inconnu.
    Qu'en pensez-vous ?

  2. #2
    Membre Expert
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Par défaut
    Bonjour,
    de ce que tu montres, struct enreg n'est pas «inconnu», puisque justement tu le déclares, mais incomplet car tu ne le définis pas. Cela signifie principalement que tu ne pourras pas l'utiliser directement pour déclarer une variable car la taille de ce type est a priori inconnu. En revanche tu pourras toujours utiliser un pointeur sur ce type car la taille d'un pointeur est elle connue.

    Maintenant ce que je peux rajouter est simplement ce que la norme C11 dit à la section 6.7.6.3 Function declarators, paragraphe 12
    If the function declarator is not part of a definition of that function, parameters may have incomplete type and may use the[*] notation in their sequences of declarator specifiers to specify variable length array types.
    Cela signifie que tu peux déclarer une fonction dont les paramètres utilisent des types incomplets.

    Un peu avant au paragraphe 7 on peut lire :
    A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. [...]
    Donc oui les déclarations sont équivalentes dans le sens où si le compilateur voit la déclaration void function_array( Ts_enreg objects[]); alors il la transforme en void function_array( Ts_enreg *objects);.

    Donc un compilateur conforme ne devrait pas râler, du moins tant que tu n'essayes pas de fournir une définition de la fonction avant de donner la définition de ton type incomplet.

    PS: Il va y avoir une toute petite différence quand tu utilises static avec une taille. Bien que les déclarations suivantes soient compatibles pour tout type T (sauf void) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void foo(size_t n, T *array);
    void foo(size_t n, T array[]);
    void foo(size_t n, T array[n]);
    void foo(size_t n, T array[*]);
    void foo(size_t n, T array[10]);
    void foo(size_t n, T array[static 10]);
    la dernière est un peu particulière car tu t'engages à fournir un paramètre array qui sera un pointeur vers au moins 10 objets de type T consécutifs en mémoire. Le compilateur pourra alors faire des hypothèses d'optimisations (comme le paramètre array ne sera pas NULL, …) qui pourraient donner des comportements aberrants si tu ne respectes pas ton engagement.

  3. #3
    Membre habitué
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2016
    Messages : 10
    Par défaut Ca s'est de la réponse !
    @picodev : merci de ta réponse complète avec citation des sources ! j'adore !

  4. #4
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    J'ai le même problème avec GCC 6.3.0.

    Bout de code testé :
    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
    #include <stdio.h>
     
    struct enreg;
    typedef struct enreg Ts_enreg;
    void function_ptr  (Ts_enreg * objects  );
    void function_array(Ts_enreg   objects[]); // error: array type has incomplete element type 'Ts_enreg {aka struct enreg}'
     
    struct enreg {};
    void function_ptr  (Ts_enreg * objects  ) {}
    void function_array(Ts_enreg   objects[]) {}
     
    int main()
    {
    #ifdef __GNUC__
    	printf("GCC version: %s\n\n", __VERSION__);
    #endif
    	return 0;
    }
    Soit c'est un bogue de GCC, soit il y a une subtilité qui m'échappe.

    D'ailleurs, toujours avec GCC 6.3.0, le même code compile très bien en C++.

  5. #5
    Membre Expert
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Par défaut
    Comme quoi il faut toujours bien chercher avant de répondre ^^

    D'après ce que je comprends, la norme impose que pour toute déclaration de tableau le type des objets ne soit pas incomplet au paragraphe 1 de la section 6.7.6.2 Array declarators :
    [...] The element type shall not be an incomplete or function type. [...]
    Et cela vaut donc apparemment aussi pour la déclaration d'un paramètre de type tableau de.

    J'ai trouvé une petite explication de pourquoi du comment dans un defect report du comité de normalisation de C qui date de 1992 (Defect Report #407) :

    Are the following declarations strictly conforming?
    /* 1 */ struct S;
    /* 2 */ struct S *f(struct S *p) {return p; }
    /* 3 */ struct S *g(struct S a[]) {return a; }

    [...]
    The function g is more interesting. A parameter of type array is adjusted to pointer type (subclause 6.7.1, page 82, lines 23-26). (Note that is an adjustment of the type of the parameter definition. It is not a conversion, as is what happens when an argument of type array is passed to a function.) Thus, the type of parameter a is pointer to struct S. This would seem to make the function g the same case as function f. However, subclause 6.1.2.5, page 23, lines 23-24 (also Footnote 17) disallow array types from having an incomplete element type (like struct S). This raises the question, is function g strictly conforming because the type of a is really pointer, or is function g not strictly conforming because a had an invalid array type before the compiler in effect rewrote the declaration?
    [...]
    Response
    First of all, no constraints are violated. Therefore, no diagnostics are required.
    Declarations 1, 2, and 5 are strictly conforming. Declarations 3, 4, and 6 are not, and therefore cause undefined behavior.
    The struct S is an incomplete type (subclause 6.5.2.3, page 62, lines 25-28). Also, an array of unknown size is an incomplete type (subclause 6.5.4.2, page 67, lines 9-10). Therefore, arrays of either of the above are not strictly conforming (subclause 6.1.2.5, page 23, lines 23-24). This makes declarations 3, 4, and 6 not strictly conforming. (But an implementation could get it right.)
    As an aside, array parameters are adjusted to pointer type (subclause 6.7.1, page 82, lines 23-24). However, there is nothing to suggest that a not-strictly-conforming array type can magically be transformed into a strictly conforming pointer parameter via this rule.
    The types in question can be interpreted two different ways. (Array to pointer conversion can happen as soon as possible or as late as possible.) Hence a program that uses such a form has undefined behavior.
    Même si là ça concerne plus une définition qu'une déclaration.

    Désolé pour la mauvaise piste !

  6. #6
    Membre habitué
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2016
    Messages : 10
    Par défaut
    Merci pour le temps passé !

    Vous avez entièrement répondu à mes interrogations !

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

Discussions similaires

  1. Différence entre un "bidouilleur" et un Pro ?
    Par christ_mallet dans le forum Débats sur le développement - Le Best Of
    Réponses: 290
    Dernier message: 28/11/2011, 10h53
  2. Réponses: 5
    Dernier message: 11/12/2002, 12h31
  3. Différence entre TCP, UDP, ICMP
    Par GliGli dans le forum Développement
    Réponses: 1
    Dernier message: 13/09/2002, 08h25
  4. Différences entre jmp, jz, jnz, etc
    Par christbilale dans le forum Assembleur
    Réponses: 3
    Dernier message: 05/07/2002, 15h09
  5. Réponses: 3
    Dernier message: 07/05/2002, 16h06

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