Interchangeabilité des types pointeur
Le
Jérôme Frgacic

Bonjour tous,
Tout d'abord, meilleurs vux pour cette anne 2013.
Dans le cas d'un petit projet personnel, je souhaite cre une liste dont =
chaque nud comporte un pointeur vers une ressource alloue et un point=
eur de fonction spcifiant la fonction permettant de librer cette ress=
ource. Ainsi, j'ai reprsent un nud l'aide de cette structure :
struct ressource {
void *data;
void (*delete)();
struct ressource * next;
};
Le problme, c'est que les ressources alloues sont stockes au sein =
d'un pointeur gnrique (pointeur sur void), mais que les fonctions de =
destructions rfrences, elles, n'attendent pas forcment un tel p=
ointeur (parfois oui, comme free, mais parfois non, comme fclose ou autre).=
Je sais que, ce sujet, la norme fourni quelques garanties pour certain=
s types de pointeurs :
C11 (n1570), 6.2.5 Types, al. 28, p. 43
> A pointer to void shall have the same representation and alignment
> requirements as a pointer to a character type. Similarly, pointers
> to qualified or unqualified versions of compatible types shall have
> the same representation and alignment requirements. All pointers to
> structure types shall have the same representation and alignment
> requirements as each other. All pointers to union types shall have the
> same representation and alignment requirements as each other. Pointers
> to other types need not have the same representation or alignment
> requirements.
mais pour le reste, rien n'est prvu. Aussi, j'aurais voulu savoir si j'a=
i des chances de tomber sur des architectures o une telle solution pose =
problme et, galement, s'il existe une autre solution, cette fois-ci p=
ortable ?
Merci d'avance pour vos rponses.
Tout d'abord, meilleurs vux pour cette anne 2013.
Dans le cas d'un petit projet personnel, je souhaite cre une liste dont =
chaque nud comporte un pointeur vers une ressource alloue et un point=
eur de fonction spcifiant la fonction permettant de librer cette ress=
ource. Ainsi, j'ai reprsent un nud l'aide de cette structure :
struct ressource {
void *data;
void (*delete)();
struct ressource * next;
};
Le problme, c'est que les ressources alloues sont stockes au sein =
d'un pointeur gnrique (pointeur sur void), mais que les fonctions de =
destructions rfrences, elles, n'attendent pas forcment un tel p=
ointeur (parfois oui, comme free, mais parfois non, comme fclose ou autre).=
Je sais que, ce sujet, la norme fourni quelques garanties pour certain=
s types de pointeurs :
C11 (n1570), 6.2.5 Types, al. 28, p. 43
> A pointer to void shall have the same representation and alignment
> requirements as a pointer to a character type. Similarly, pointers
> to qualified or unqualified versions of compatible types shall have
> the same representation and alignment requirements. All pointers to
> structure types shall have the same representation and alignment
> requirements as each other. All pointers to union types shall have the
> same representation and alignment requirements as each other. Pointers
> to other types need not have the same representation or alignment
> requirements.
mais pour le reste, rien n'est prvu. Aussi, j'aurais voulu savoir si j'a=
i des chances de tomber sur des architectures o une telle solution pose =
problme et, galement, s'il existe une autre solution, cette fois-ci p=
ortable ?
Merci d'avance pour vos rponses.
Il ne reste pas grand chose dans "le reste"... ca couvre les pointeurs
de fonction, en fait. C'est le cas un peu bizarre en C, mais tant que
tu ne manipules que des pointeurs sur autre chose que du code, tout
ceci est tres portable.
Pour le reste, cote cast entre pointeurs, tu peux avoir des problemes
d'aliasing si tu ne passes pas un des types etiquette comme "pointeur
generique", c'est-a-dire void*, char* et assimiles. Donc dans ton cas,
zero probleme.
[couic]
Euh, si. 6.3 /Conversions/, § 6.3.2.3 /Pointers/, al. 1 :
A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to
a pointer to void and back again; the result shall compare
equal to the original pointer.
En gros, tant que ton code manipule des pointeurs génériques et que
derrière il y a des pointeurs vers des types _objets_, tout va bien.
Il faut bien comprendre que si dans ton code tu écris
FILE* f;
ptr_ress->data = f;
il y a conversion de FILE* à void* ; et quand tu écris plus tard
fclose( (FILE*)(ptr_ress->data) );
la conversion de retour (/back/) est même explicite !
En règle générale les représentations et les alignements sont bien
entendu identiques ; mais dans les cas où il y a des différences (genre
des pointeurs vers char sur 48 bits quand un pointeur vers struct est
sur 32 bits; ou les pointeurs _far* ou _segment* qui firent la joie des
programmeurs PC des années 1985-1990...), c'est le problème du
compilateur, pas celui de la norme, ni du programmeur qui la suit.
Antoine
En C, tu n'as pas besoin de la conversion de retour. J'aurais meme tendance
a dire qu'elle est nefaste, puisqu'elle peut masquer une erreur si ton
type de depart n'est pas un pointeur.
Je sais que c'est sans doute une mauvaise habitude heritee du C++, ou meme
une envie de faire dans la compatibilite gratuite.
J'aurais bien envie de dire que si vraiment tu veux la compatibilite,
ca vaut le coup de cacher ca derriere une macro:
#ifdef __cplusplus
#define voidp_cast(T, v) reinterpret_cast<T>(v)
#else
#define voidp_cast(T, v) (v)
#endif
fclose(voidp_cast(FILE *, ptr_ress->data));
Ou simplement l'idee que c'est plus logique de marquer les conversions
non sures ;)
A+
--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
... mais plus dangereux, puisque ton compilo acceptera aussi bien.
void *p;
struct a *q;
q = (struct a *)p;
que
int p;
struct a *q;
q = (struct a *)p;
...
En fait, mon problème est que la libération de la ressource est f aite
via le pointeur de fonction « delete » de la structure. Autrement dit,
pour chaque ressource, on a un appel du type :
ptr_ressâ>delete(ptr_ressâ>data);
Or, si cela ne pose pas de problème quand la fonction référe ncée est
free, câest plus gênant sâil sâagit de fclose car elle reçoit un objet
de type « pointeur sur void » alors quâelle attend un obj et de type «
pointeur sur structure ».
Je me demande donc si une telle technique pose, de manière génà ©rale,
un problème (appremment non) et sâil nâexiste pas une alternative qui
ne pose pas de problèmes de portabilité.
Marc Espie a écrit :
Ben, disons que, en théorie, il reste : les pointeurs sur tous les
types natifs (sauf void et char), les pointeurs de pointeur, les
pointeurs sur tableau et les pointeurs de fonction.
Mais, si je comprend bien, dans la réalité, tous les pointeurs on t
généralement la même taille sauf les pointeurs de fonctions ?
Non, il faut que tu relises attentivement ce que la norme appelle un objet
dans ce contexte precis.
Ca couvre tout sauf les pointeurs de fonction...
Jâavoue que je suis un peu perdu là ... Lorsque je lis ce pass age :
Je comprends que la norme nous garantit que, ont la même taille et le
même alignement :
â un pointeur sur char et un pointeur sur void ;
â un pointeur sur un type et un pointeur sur le même type qualifié ;
â un pointeur sur structure et un pointeur sur une autre struct ure ;
â un pointeur sur union et un pointeur sur une autre union.
Pour le reste, la norme ne nous dit rien, ce qui signifie, pour moi,
que rien ne me garantit quâun pointeur sur une structure à la même
taille et le même alignement quâun pointeur sur void et que, p ar
conséquent, le code suivant a un comportement indéterminé :
#include
struct coord {
int x;
int y;
};
static void print_ptr();
int
main(void)
{
struct coord coord;
struct coord *p = &coord;
print_ptr(p);
return 0;
}
static void
print_ptr(void *p)
{
printf("%pn", p);
}
me trompéâje ?
Très juste, cela m'avait échappé.
Antoine