Je suis nouveau sur Linux. J'utilise gcc
(Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 sur Ubuntu 12.04 LTS. Lorsque j'ai compilé le programme c à l'aide d'un pointeur, j'ai reçu l'avertissement -Wformat
comme indiqué ci-dessous. Mais si j'exécute le fichier a.out
, j'obtiens le résultat correct. Quelqu'un peut-il me dire, s'il vous plaît, pourquoi j'ai reçu le message et me suggérer ce que je devrais faire pour vaincre?.
Mon programme de test:
#include<stdio.h>
void main(void)
{
int x=10,y,z;
int *p=&x ;
printf("\n\np = %u\n",p);
printf("\n*p = %u\n",*p);
printf("\n&x = %u\n",&x);
printf("\n&y = %u\n",&y);
printf("\n&z = %u\n",&z);
printf("\n&p = %u\n\n",&p);
}
Sortie:
qust1-Array.c:11:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:14:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:15:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:16:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:17:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat]
Vous recevez les avertissements car vous utilisez en utilisant un spécificateur de format incorrect dans printf()
. p
est un pointeur entier. &p
est l'adresse d'un pointeur. &x
et &y
sont des adresses d'entiers. Ce sont toutes les adresses en mémoire, pas les valeurs d'une variable. Le spécificateur %u
concerne les valeurs des entiers non signés. Donc, vous imprimez des pommes là où le compilateur attend des oranges. Les adresses sont plus courtes que certaines valeurs stockées dans des variables. En utilisant %u
, vous imprimerez une valeur d'adresse décimale (très inhabituelle) et quelques données supplémentaires situées derrière celle-ci en mémoire. Le compilateur se plaint, car ce n'est probablement pas ce que vous voulez faire. Pour imprimer les adresses, utilisez le spécificateur %p
, comme dans:
printf("\n&x = %p\n",&x);
En plus de cela, vos variables sont des entiers signés et doivent donc utiliser %i
au lieu de %u
. Le spécificateur de format %u
de printf()
concerne uniquement les entiers positifs. Pour les petites valeurs positives, %i
et %u
sont interchangeables. L'avertissement est affiché car le type de variable ne correspond pas à son spécificateur, ce qui pose parfois des problèmes.
Ce serait plus judicieux de vos types de variables:
printf("\n\np = %p\n", p); // p is a pointer so %p would print the address
printf("\n*p = %i\n", *p); // the data saved at that address is an integer
// so %i is appropriate if you dereference the
// pointer with the star "*p"
printf("\n&x = %p\n", &x); // &x gives the address of the integer variable x
// so %p is the specifier for that address
printf("\n&y = %p\n", &y);
printf("\n&z = %p\n", &z);
printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is
// stored -> still an address -> %p is the right
// specifier
Un peu de fond sur les entiers et les pointeurs signés et non signés:
C utilise le même 32 bits (ou une autre puissance de deux selon l'architecture du système) pour stocker les entiers non signés et signés. Donc le plus élevé unsigned int
est 232-1 ou en notation binaire:
232-1 = (1111111111111111111111111111111111)2 <non signé)
Et le numéro un ressemblerait à ceci en binaire:
1 = (00000000000000000000000000000001)2 <- (non signé)
Maintenant normal --- (entiers signés besoin de stocker les nombres négatifs aussi, mais toujours dans le même espace de 32 bits. Si vous avez mémorisé le signe, du nombre dans, par exemple, Au début, vous perdriez un peu. Ce serait un gaspillage, par exemple le zéro aurait deux représentations comme + et - zéro. Pour contourner ce problème les nombres négatifs dans les entiers signés sont stockés un peu différemment: Pour coder un nombre dans un entier signé, vous ajoutez en deux la plage possible pour votre nombre de 32 bits. C'est 2(32-1), puis utilisez la représentation binaire régulière de ce nouveau numéro. Donc, un est codé comme 2(32-1) + 1 serait pour un entier non signé. On a:
2(32-1) = (1111111111111111111111111111111111)2 <-signé
...
1 = (10000000000000000000000000000001)2 <- signé
0 = (10000000000000000000000000000000)2 <- signé
-1 = (0111111111111111111111111111111111)2 <- signé
...
-2(32-1) = (00000000000000000000000000000000)2 <-signé
Maintenant, vous avez codé le même nombre d’entiers, mais le maximum pour les entiers signés est par conséquent seulement 2(32-1) par opposition au double, 232-1, pour les entiers non signés. Ceci est appelé représentation K-excédent ou binaire offset pour les nombres négatifs. La plupart des systèmes utilisent le complément à deux, où le premier bit le plus significatif est inversé.
Pour voir cela, définissez x=-1;
puis printf("%u",x)
. Vous obtiendrez le résultat suivant:
2147483648
Qui est 232-1 ou (0111111111111111111111111111111111)2 en notation binaire. Pour le complément à deux, ce nombre serait:
4294967295
Ou 232-1. Cela équivaut à (1111111111111111111111111111111111)2 en binaire, le premier bit est donc inversé par rapport à la valeur de K en excès de 2147483648 ci-dessus.
C'est donc comment les données sont stockées. Les pointeurs entrent en jeu lorsque vous pensez à où. Les bits physiques dans la mémoire doivent avoir des adresses. Puisqu'ils sont incroyablement nombreux, vous les abordez par tranches de plus d'un bit. Si vous créez un pointeur, la mémoire physique située à l'adresse du pointeur contient une autre adresse en mémoire. Une maison est donc un objet physique, un peu comme un peu dans la mémoire de votre PC. Un morceau de papier serait un pointeur. Il est plus petit que la maison, mais peut contenir l'adresse d'une maison ou d'autres maisons. Dans cette analogie, ci-dessus, vous auriez essayé de démolir le morceau de papier au lieu de la maison actuelle et c'était en fait une montagne ...