Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Interchangeabilité des types pointeur

18 réponses
Avatar
Jérôme Frgacic
Bonjour =E0 tous,

Tout d'abord, meilleurs v=9Cux pour cette ann=E9e 2013.

Dans le cas d'un petit projet personnel, je souhaite cr=E9e une liste dont =
chaque n=9Cud comporte un pointeur vers une ressource allou=E9e et un point=
eur de fonction sp=E9cifiant la fonction permettant de lib=E9rer cette ress=
ource. Ainsi, j'ai repr=E9sent=E9 un n=9Cud =E0 l'aide de cette structure :

struct ressource {
void *data;
void (*delete)();
struct ressource * next;
};

Le probl=E8me, c'est que les ressources allou=E9es sont stock=E9es au sein =
d'un pointeur g=E9n=E9rique (pointeur sur void), mais que les fonctions de =
destructions r=E9f=E9renc=E9es, elles, n'attendent pas forc=E9ment un tel p=
ointeur (parfois oui, comme free, mais parfois non, comme fclose ou autre).=
Je sais que, =E0 ce sujet, la norme fourni quelques garanties pour certain=
s types de pointeurs :

C11 (n1570), =A7 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 pr=E9vu. Aussi, j'aurais voulu savoir si j'a=
i des chances de tomber sur des architectures o=F9 une telle solution pose =
probl=E8me et, =E9galement, s'il existe une autre solution, cette fois-ci p=
ortable ?=20

Merci d'avance pour vos r=E9ponses.

10 réponses

1 2
Avatar
espie
In article ,
Jérôme Frgacic wrote:
Bonjour à tous,

Tout d'abord, meilleurs vœux pour cette année 2013.

Dans le cas d'un petit projet personnel, je souhaite crée une liste dont
chaque nœud comporte un pointeur vers une ressource allouée et un
pointeur de fonction spécifiant la fonction permettant de libérer cette
ressource. Ainsi, j'ai représenté un nœud à l'aide de cette structure :

struct ressource {
void *data;
void (*delete)();
struct ressource * next;
};

Le problème, c'est que les ressources allouées sont stockées au sein
d'un pointeur générique (pointeur sur void), mais que les fonctions de
destructions référencées, elles, n'attendent pas forcément un tel
pointeur (parfois oui, comme free, mais parfois non, comme fclose ou
autre). Je sais que, à ce sujet, la norme fourni quelques garanties pour
certains 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 prévu. Aussi, j'aurais voulu savoir si
j'ai des chances de tomber sur des architectures où une telle solution
pose problème et, également, s'il existe une autre solution, cette
fois-ci portable ?



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.
Avatar
Antoine Leca
Jérôme Frgacic écrivit :
Le problème, c'est que les ressources allouées sont stockées au sein d'un
pointeur générique (pointeur sur void), mais que les fonctions de
destructions référencées, elles, n'attendent pas forcément un tel pointeur
(parfois oui, comme free, mais parfois non, comme fclose ou autre). Je
sais que, à ce sujet, la norme fourni quelques garanties pour certains
types de pointeurs :

C11 (n1570), § 6.2.5 Types, al. 28, p. 43


[couic]

mais pour le reste, rien n'est prévu.



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
Avatar
espie
In article <kcgo07$shm$,
Antoine Leca wrote:
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 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));
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Je sais que c'est sans doute une mauvaise habitude heritee du C++, ou meme
une envie de faire dans la compatibilite gratuite.



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
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
(Marc Espie) writes:

Je sais que c'est sans doute une mauvaise habitude heritee du C++, ou meme
une envie de faire dans la compatibilite gratuite.



Ou simplement l'idee que c'est plus logique de marquer les conversions
non sures ;)



... 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;


...
Avatar
J
Antoine Leca a écrit :
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 tar d
fclose( (FILE*)(ptr_ress‐>data) );
la conversion de retour (/back/) est même explicite !



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 :
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 tan t que
tu ne manipules que des pointeurs sur autre chose que du code, tout
ceci est tres portable.



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 ?
Avatar
espie
In article ,
Jérôme Frgacic wrote:
Marc Espie a écrit :
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.



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.



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...
Avatar
J
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 :

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.



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 <stdio.h>

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 ?
Avatar
espie
In article ,
Jérôme Frgacic wrote:
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 passage :

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.



Je comprends que la norme nous garantit que, ont la même taille et le
même alignement :

â€
Avatar
Antoine Leca
Marc Espie écrivit :
In article <kcgo07$shm$,
Antoine Leca wrote:
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 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.



Très juste, cela m'avait échappé.


Antoine
1 2