Question

Existe-t-il un moyen de déterminer de manière portable la limite supérieure et inférieure des valeurs de pointeur vide dans ANSI C89 / ISO C90? (Je n'ai actuellement pas de copie de la norme avec moi (j'ai Bien sûr, si les valeurs de pointeur de vide sont garanties non signées, cette tâche est triviale (via sizeof (void *)), mais je ne me souviens pas si cela est garanti ou non. Je peux penser à quelques très inefficaces algorithmes (incrémentation jusqu’à débordement, etc.), mais je voudrais savoir si quelqu'un dispose d’un moyen relativement peu coûteux (en termes de complexité temporelle) et portable de calculer ces limites.

- EDITER -

En outre: existe-t-il un moyen portable de déterminer la validité des valeurs du pointeur?

Pourquoi : cela a été abordé lors d'une discussion avec un collègue et m'a laissé perplexe. Je ne sais pas sur quoi il travaille, mais je veux juste savoir parce que ça m'intéresse! : -)

Était-ce utile?

La solution

Il n’existe aucun moyen portable de déterminer si un pointeur donné est valide ou non. Vous devez savoir à quel type de système de mémoire vous avez affaire. En fonction du système d'exploitation et du processeur, il peut y avoir ou non un moyen d'interroger les tables de pages du gestionnaire de mémoire virtuelle pour déterminer les plages de pointeurs valides.

Par exemple, sous Linux, vous pouvez examiner le fichier spécial mmap sous / proc pour obtenir le mappage de mémoire virtuelle d'un processus. Voici un exemple de cat qui lit sa propre carte mémoire:

$ cat /proc/self/mmap
08048000-0804c000 r-xp 00000000 09:00 5128276                            /bin/cat
0804c000-0804d000 rw-p 00003000 09:00 5128276                            /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0                                  [heap]
f7ca7000-f7e40000 r--p 00000000 09:00 3409654                            /usr/lib/locale/locale-archive
f7e40000-f7e41000 rw-p f7e40000 00:00 0 
f7e41000-f7f68000 r-xp 00000000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f68000-f7f6d000 r--p 00127000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6d000-f7f6f000 rw-p 0012c000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6f000-f7f72000 rw-p f7f6f000 00:00 0 
f7f83000-f7f85000 rw-p f7f83000 00:00 0 
f7f85000-f7f9a000 r-xp 00000000 09:00 2637871                            /lib/ld-2.3.6.so
f7f9a000-f7f9c000 rw-p 00014000 09:00 2637871                            /lib/ld-2.3.6.so
ff821000-ff836000 rw-p 7ffffffea000 00:00 0                              [stack]
ffffe000-fffff000 r-xp ffffe000 00:00 0                                  [vdso]

Vous pouvez voir les plages de pointeurs valides, ainsi que les bits indiquant si la mémoire est (r) lisible, (w) ritable, e (x) ecutable ou (p) renvoyée (c'est-à-dire non paginée sur le disque) .

Autres conseils

La spécification garantit que les pointeurs sont non signés. Mais pourquoi diable voulez-vous trouver les limites? "Tout entre 0x00000001 et 0xffffffff &"; n’est pas vraiment un test utile, car le nombre de pointeurs valides sera un sous-ensemble infime de celui-ci.

void * est toujours assez grand pour contenir un pointeur sur la mémoire adressable. Toute autre utilisation est strictement interdite par l’association des ligues majeures de baseball.

Exemple: le dec-10 était une architecture de 36 bits avec des mots de 36 bits. Cependant, les adresses étaient de 18 bits et vous pouviez contenir 2 pointeurs dans n’importe quel registre / mot.

Ouais - c'est un exemple extrême. Si vous devez faire des calculs avec des pointeurs, sizeof est valide. mais faire le pointage math sur autre chose qu'un tableau contigu est plus dodgier que dodgy.

Enfin, n'utilisez jamais un 'void *' pour stocker un pointeur sur un objet ou un membre à membre en C ++. De nombreuses implémentations de compilateur utilisent en réalité plusieurs pointeurs «physiques» pour implémenter plusieurs héritages de classes concrètes (ou partiellement concrètes). En réalité, cela ne vient presque jamais parce que très peu de personnes utilisent l'héritage multiple de cette manière, et lorsqu'elles le font, les pointeurs sont rarement utilisés. Quand cela se produit, il est vraiment difficile de comprendre ce qui s'est passé.

Vous devez déterminer la valeur entière vers laquelle un void * peut être transtypé à partir du modèle de bits réel en mémoire - la conversion d'un void * en un type entier peut impliquer conversions!

En supposant que sizeof (void *) == sizeof (long) , pour un void * p , il est possible que ce qui suit soit faux:

((long)p) == *((long *)&p)

En outre, la norme ne spécifie pas si même est un type entier suffisamment grand pour contenir les valeurs de tous les pointeurs valides!

Par conséquent, il n’existe aucun moyen portable de faire ce que vous voulez faire ...

Hormis une région qui correspond à NULL, il n'y a aucune restriction (portable) sur les adresses de mémoire. Un système d’exploitation suffisamment durci pourrait utiliser divers mécanismes CPU / SE pour fournir à chaque processus des adresses aléatoires et bien distribuées à chaque appel de malloc (), et un exécutable indépendant de la position plus ASLR peut également exécuter le code à partir de n’importe quelle adresse.

Je sais que sur Win32, les pointeurs 64 bits sont étendus. Il est amusant d’inspecter un minidump 32 bits à partir d’une machine 64 bits si vous ne signez pas de pointeur étendu.

Voir ici pour en savoir plus sur 64 pointeur sur un bit ( POINTER_64 ) fonctionne sur Win32.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top