2
votes

c - pointeur const vers les données const (gcc - spécificateur de déclaration 'const' dupliqué)

Je programme un module sur un microcontrôleur pour interfacer son EEPROM pour recevoir des données utilisateur à partir de là. Comme vous ne pouvez pas facilement écraser l'EEPROM, je souhaite renvoyer un pointeur const vers les données const .

Maintenant, mon prototype de fonctions ressemble à ceci:

const struct userData const * getEEPROMDataAtIndex (uint32_t uidIndex)

tandis que gcc me dit dupliquer le spécificateur de déclaration 'const' [-Wduplicate-decl-specifier] . Chaque const que j'utilise ne devrait-il pas avoir un effet différent? L'un pour rendre les données pointées immuables, l'autre pour que le pointeur reçu ne soit pas redirigé?


2 commentaires

Quand j'utilise const struct userData * const getEEPROMDataAtIndex (uint32_t uidIndex) j'obtiens qualificatifs de type ignorés sur le type de retour de fonction [-Wignored-qualifiers] comme avertissement. Dans la sortie, la flèche ^ ~~~~ pointe vers le premier const, donc ce ne serait plus qu'un pointeur cont maintenant avec les données derrière, non?


Il n'y a pas de valeurs const dans C; par conséquent. int const foo (void); est identique à int foo (void); . Cela ne change pas si vous remplacez int par const struct userdata *


4 Réponses :


-3
votes

Je suggère d'utiliser typdef pour saisir votre type de données de retour. Ensuite, dans la déclaration de fonction, il vous suffit de déclarer le type de retour comme nom de typedef.

Par exemple ...

typedef struct USER_DATA
{
....
...
};

Je pense que cela simplifierait un peu les choses. que se passe-t-il si vous échangez ' const struct ' ... en ' struct const '?


2 commentaires

Passez à struct const uid_t * const getPersisitedUIDAtIndex (uint32_t uidIndex); ne compile pas en donnant attendu '{' avant 'const' . J'accepte d'utiliser un typedef plus tard, mais en l'omettant ici pour plus de simplicité.


typedef ing n'est pas lié à cette question, donc il n'y ajoute rien.



5
votes

Vous avez déclaré votre structure const deux fois. Comme cela n'a pas de sens de rendre le pointeur const dans un type de retour, supprimez simplement l'une des déclarations const. Si vous vouliez rendre le pointeur const (ce qui n'a pas vraiment de sens dans un type de retour), vous mettriez const après l'astérisque.


0 commentaires

4
votes

Vous semblez manquer de compréhension sur const, par exemple.

const struct userData * const myp = getEEPROMDataAtIndex(index);
//                       ^ this declare the pointer itself (myp) cannot be changed

gcc donnera une erreur indiquant que

const struct userData * getEEPROMDataAtIndex(uint32_t uidIndex);
//this const declare the returned pointer point to something cannot be changed

pour votre but, si je comprends bien, vous devez définir la fonction comme

x.c: In function ‘main’:
x.c:8:9: error: assignment of read-only location ‘*pa’
     *pa = 4;
         ^

puis lorsque vous lancez votre pointeur constant en appelant cette fonction

#include <stdio.h>
int main()
{
    int a=123, b=456;
    const int *pa = &a;
    pa = &b;    //legal 
    *pa = 4;    //illegal
    printf("a=%d\n", a);
    return 0;
}


4 commentaires

Ok, j'ai compris. Merci beaucoup! Mais pour moi, effectivement, cela signifie que l'appelant est responsable de rendre le pointeur const, ce que je voulais faire automatiquement par le type de retour de la fonction ... Cela signifie que je ne peux pas garantir qu'un pointeur retourné pointe vers des données constantes au niveau de l'interface (type de retour)?


vous avez renvoyé une valeur (pointeur) vers le monde extérieur de cette fonction, et elle est affectée à une 2ème variable (un autre pointeur), je ne pense pas que vous puissiez contrôler la 2ème variable si elle est modifiable, elle est hors de portée.


@ PaulWürtz Je ne vois pas en quoi il serait utile d'exiger que le pointeur assigné soit constant. La structure pointée est toujours constante et vous devrez effectuer un moulage de pointeur fragmentaire si vous souhaitez modifier la structure. Woo hoo je suis maintenant autorisé à commenter, merci beaucoup.


Je ressens le besoin d'ajouter que la fonction déclare pour renvoyer le pointeur const est informative, pas obligatoire, comment utiliser ce pointeur est à l'appelant.



-2
votes

const struct userData const * => const struct userData * const

Il peut être utilisé lors de l'initialisation de la variable automatique:

const struct userData * const foo(void);

void bar(void)
{
    const struct userData *const ptr_to_something = foo();

    /* some code */ 
}


7 commentaires

Il y a un étrange caractère non imprimable après le «=» dans votre réponse, et peut-être que votre réponse est trop «sèche»? (Je n'ai pas DV ^^)


Je ne sais pas pour le vote vers le bas, mais que pensez-vous que const struct userData * const fait quand l'OP déclare une fonction? Les fonctions renvoient des valeurs. const n'affecte que lvalues ​​- il indique qu'un objet ne changera pas. Par exemple, si vous avez const int x = 4; , cela signifie que x ne changera pas. Mais une fonction renvoie simplement une valeur, comme 4. Une valeur n'est qu'une valeur, pas un objet qui peut changer. Donc const n'a aucun effet sur lui. Selon C 2018 6.7.3 5, «Les propriétés associées aux types qualifiés ne sont significatives que pour les expressions qui sont des valeurs l.»


@EricPostpischil const struct userData * const foo (); essayez cdecl.org et voyez à nouveau ma réponse


Vote de suppression intéressant. Une explication? Vengeance ou mauvaise journée?


La question d’OP porte sur la déclaration d’une fonction. La déclaration d'un objet n'est pas pertinente. cdecl.org n'est pas pertinent; il n'est pas contesté que le type est nominalement qualifié de const. C'est juste que le qualificatif n'a pas de sens pour une déclaration de fonction.


Déclaration de la fonction: const struct userData * const foo (void);


Qu'est-ce que votre exemple de godbolt.org est censé prouver?