Veuillez considérer le programme suivant. Étant donné quatre pointeurs différents, il les imprime comme non signés.

#include<stdio.h>

typedef unsigned long ulong;

int main(){
    char        *pc = NULL;
    int         *pi = NULL;
    double      *pd = NULL;
    long double    *pld = NULL;
    printf("%5lu%5lu\n%5lu%5lu\n%5lu%5lu\n%5lu%5lu\n",
        (ulong)(pc + 1),(ulong)(pi + 1),
        (ulong)(pd + 1),(ulong)(pld + 1),  
        (ulong)(pc + 1),(ulong)(pld + 1)
        (ulong)(pc), (ulong)(pc));
    return 0;
}

Eh bien, je ne suis pas totalement sûr d'avoir donné aux résultats le sens correct:

1    4
8   16
1   16
0    0

Avec pc + 1 et pi + 1, nous avons respectivement 1 et 4. Mon système, très probablement, attribue 1 octet pour un pointeur sur char et 4 pour un pointeur sur int. Sur cette base, j'ai déduit que le programme me donne la quantité de mémoire allouée mise à disposition de ces pointeurs.

Mais pc et pi renvoient tous les deux zéro. Pourquoi? Si ma déduction était correcte, est-ce que 1 et 4 octets de mémoire ne devraient en aucun cas être attribués à pc et pi?

1
Worice 28 nov. 2017 à 12:30

3 réponses

Meilleure réponse

Votre attente est un peu étrange:

Si ma déduction était correcte, ne faudrait-il en aucun cas attribuer 1 et 4 octets de mémoire à pc et pi?

Il n'y a pas de "mémoire assignée" à un pointeur. Un pointeur est simplement un objet contenant une adresse . Il peut s'agir de l'adresse d'un objet réellement utilisable ou non valide. S'il s'agit de NULL, il est garanti qu'il n'est pas valide.

Les représentations de différents types de pointeurs peuvent être différentes, bien qu'elles le soient rarement dans la pratique. Si tel est le cas, il est garanti que vous pouvez convertir NULL de types différents entre eux, il restera un pointeur nul . En dehors de cela, le compilateur utilise les informations de type associées à un pointeur pour calculer les indices. Si vous ajoutez 1 à un pointeur pointant vers un type de taille 8, la valeur réelle augmentera de 8.

Les deux citations suivantes de la norme semblent pertinentes pour votre question:

§6.3.2.3 p3 :

Une expression constante entière avec la valeur 0, ou une telle expression convertie en type void *, s'appelle une constante de pointeur nul . Si une constante de pointeur nul est convertie en type de pointeur, le pointeur résultant, appelé pointeur nul , est garanti pour comparer des inégalités vers un pointeur vers un objet ou une fonction.

§6.3.2.3 p6 :

Tout type de pointeur peut être converti en type entier. Sauf comme indiqué précédemment, le résultat est défini par l'implémentation. Si le résultat ne peut pas être représenté dans le type entier, le comportement n'est pas défini. Le résultat n'a pas besoin d'être dans la plage de valeurs de n'importe quel type entier.

Donc, votre code est défini par l'implémentation . La conversion de 0 en void * vous donne un pointeur nul , il n'est donc pas déraisonnable que la conversion d'un pointeur nul en un type entier donne effectivement 0, mais ce n'est pas t garanti.

À proprement parler, les expressions ajoutant un décalage à NULL sont même un comportement indéfini : pour que l'arithmétique du pointeur soit bien définie, le résultat de l'expression doit pointer vers un élément de tableau existant ou un passé cela - c'est bien sûr impossible avec NULL qui n'est pas un pointeur valide en premier lieu.

3
28 nov. 2017 à 10:00

L'arithmétique du pointeur sur un pointeur ne pointant pas sur un tableau est un comportement indéfini. Vous pourriez donc recevoir tous les résultats dans les 3 premières lignes de sortie, puisque tous vos pointeurs pointent vers NULL.

La 4ème ligne de sortie imprime simplement la valeur de NULL sur votre plate-forme qui est 0 dans la plupart des implémentations, mais n'est pas non plus standard.

Pour obtenir les tailles, utilisez simplement sizeof(char), sizeof(int) etc.

2
Anton Malyshev 28 nov. 2017 à 09:37

Vous imprimez pc sans rien y ajouter, donc en gros, vous imprimez NULL renvoyé vers (le type non standard) ulong, ce qui vous donne 0. Ce n'est pas un résultat déraisonnable, car "tous les bits à zéro" pourrait être la façon dont le compilateur implémente NULL, et faire une conversion simple bit à bit en un entier non signé vous donnerait zéro.

3
unwind 28 nov. 2017 à 09:35
47528069