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

calcul sur un pointeur invalide ?

2 réponses
Avatar
Manuel Pégourié-Gonnard
Bonjour,

Dans certains cas il peut être commode d'avoir des tableaux indexés en
partant de 1, par exemple pour voir un tableau comme un arbre binaire
avec les fils de l'élément i aux index 2i et 2i + 1 plutôt que 2 * i + 1
et 2 * i + 2, et le parent à l'index i / 2 plutôt que (i + 1) / 2 - 1.

Est-il possible dans ce but d'utiliser un pointeur pointant *avant* le
début du tableau comme base pour faire les calculs ? Par exemple :

void heapsort(void *array, size_t nel, size_t width, compar_t *compar) {
char * const base1 = (char *) array - width;
/* la suite du code calculant à partir de base1
* mais ne déréférençant que base1 + 1 * width à base1 + nel * width
* et bien sûr jamais base1
*/

Je viens d'essayer de chercher dans la norme C99 [*] à ce sujet, et il
me semble que la réponse se trouve en 6.5.6, alinéa 8 :

> When an expression that has integer type is added to or subtracted
> from a pointer, [...] If both the pointer operand and the result point
> to elements of the same array object, or one past the last element of
> the array object, the evaluation shall not produce an overflow;
> otherwise, the behavior is undefined.

Donc j'ai l'impression que le code ci-dessus a un comportement indéfini.
Est-ce bien le cas, ou est-ce que j'interprète mal la norme ?

[*] J'utilise le document N1256 (C99 + TC3) : est-ce utile de le
préciser ou bien toutes les versions de C99 ont la même numérotation ?

--
Manuel Pégourié-Gonnard - http://people.math.jussieu.fr/~mpg/

2 réponses

Avatar
espie
In article <jei37t$98j$,
Manuel Pégourié-Gonnard wrote:
Bonjour,

Dans certains cas il peut être commode d'avoir des tableaux indexés en
partant de 1, par exemple pour voir un tableau comme un arbre binaire
avec les fils de l'élément i aux index 2i et 2i + 1 plutôt que 2 * i + 1
et 2 * i + 2, et le parent à l'index i / 2 plutôt que (i + 1) / 2 - 1.

Est-il possible dans ce but d'utiliser un pointeur pointant *avant* le
début du tableau comme base pour faire les calculs ? Par exemple :

void heapsort(void *array, size_t nel, size_t width, compar_t *compar) {
char * const base1 = (char *) array - width;
/* la suite du code calculant à partir de base1
* mais ne déréférençant que base1 + 1 * width à base1 + nel * width
* et bien sûr jamais base1
*/

Je viens d'essayer de chercher dans la norme C99 [*] à ce sujet, et il
me semble que la réponse se trouve en 6.5.6, alinéa 8 :

When an expression that has integer type is added to or subtracted
from a pointer, [...] If both the pointer operand and the result point
to elements of the same array object, or one past the last element of
the array object, the evaluation shall not produce an overflow;
otherwise, the behavior is undefined.



Donc j'ai l'impression que le code ci-dessus a un comportement indéfini.
Est-ce bien le cas, ou est-ce que j'interprète mal la norme ?



Oui, c'est bien ca.

Le seul cas de pointeur "invalide" que tu as le droit d'utiliser, c'est
effectivement &(t[n]) pour un tableau de taille n (histoire de pouvoir
refaire le classique for (i = 0; i != n; i++) avec les pointeurs).

-> si tu veux vraiment des tableaux indexes a 1 de facon portable, il va
falloir perdre une case.

Si j'ai bonne memoire, le rationale associe a la norme specifie bien qu'il
existe des implementations ou ecrire un *pointeur* invalide suffit a planter
le programme... je n'en ai pas rencontre personnellement, mais je ne me
m'amuserais pas a perdre la conformite pour une case...
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Si j'ai bonne memoire, le rationale associe a la norme specifie bien qu'il
existe des implementations ou ecrire un *pointeur* invalide suffit a planter
le programme... je n'en ai pas rencontre personnellement, mais je ne me
m'amuserais pas a perdre la conformite pour une case...



x86. Mais en mode segmenté, qui n'est plus utilisé à ma connaissance par
personne (utiliser un segment par allocation était plus ou moins le modèle
sous-jacent à la conception des segments, un des problèmes à l'utiliser
maintenant serait le nombre de segments qui est ridiculement petit pour les
normes actuelles, un autre le coût en perf; il y a d'autres architectures,
mais je doute qu'il y ai beaucoup d'utilisateurs de C sur celles-là, ça
tient du retro-computing même si la dernière fois que j'ai regardé, Unisys
en vendait toujours un modèle).

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org