Apprendre le hacking #5 // Des variables magiques
Sommaire
- Présentation
- Des signatures ... Ou pas. Du long ... Ou pas.
- Des variables magiques
Présentation
Bonjour à tous et à toutes, la semaine dernière nous avons appris à créer mais surtout utiliser des pointeurs. J'éspère que en addition à mon article, vous avez pris le temps de mener vos propres recherches. En effet, même si nous allons encore nous attarder sur deux trois explication des pointeurs, je considère cette notion comme acquise.
Aujourd'hui nous allons voir qu'il est possible de modifier le type d'une variable. Bon, dit comme ça, ça peut parraître idiot mais nous allons voir que cela va pouvoir corriger bien des erreurs. En effet cela va être bien plus pratique avec les pointeurs. Mais tout d'abord voyons deux trois trucs bien cools sur les valeurs numériques.
De quoi allez-vous avoir besoin ?
Comme d'habitude, pour les nouveaux il vous faudra les bases en programmation. En allant sur mon profil vous allez trouver quelques articles assez rapides que vous allez pouvoir lire en diagonale. Sinon, pour les autres, il va falloir créer un nouveau répertoire dans le dossier du cours.
Et bien évidemment de votre magnifique cerveau. Ce cerveau qui vous permettra de faire tout ce que vous désirez quand vous saurez tout ce qu'il faut savoir.
Et enfin, il va falloir télécharger pcalc, une calculatrice pour programmeur qui affiche les résultat en décimal, héxa et binaire. Allez donc sur intenret depuis votre Linux à l'adresse suivante : https://sourceforge.net/projects/pcalc/
Une fois téléchargé on extrait le dossié obtenu.
On se positionne ensuite dans le dossier décompressé.
On procède à l'installation de flex:
Et enfin :
Des signatures ... Ou pas. Du long ... Ou pas.
En C, les valeurs numériques peuvent êtres négatives ou positives. On dit alors qu'elles sont signées. Il y a cependant des valeurs qui sont non_signées. C'est à dire qu'elle ne peuvent pas êtres négatives. Toutes les valeurs numériques doivent êtres enregistrées dans un format binaire. Par exemple, un entier 32 bits non signé peut contenir des valeurs allant de 0 (uniquement des 0) à 4 294 967 295 (uniquement des 1). Les entiers 32 bits signés peuvent eux aller de -2 147 483 648 à 2 147 483 648. L'un des bits va servir à savoir si la valeur est positive ou négative. Les valeurs positives sont semblables aux non signées.
En revanche, et c'est la que ça prend la tête, les valeur négative sont stockée en utilisant la méthode du complément à deux. Je m'explique, dans la méthode du complément à deux, lorsque une valeur négative est ajoutée à un nombre positif de la même grandeur, le résultat est égal à 0. Donc, le nombre négatif est tout d'abord écrit comme un nombre positif binaire, puis tous les bits sont inversés et 1 est ajouté au résultat. Oui ça prend la tête mais ceci permet aux nombres négatifs d'être ajoutés à des nombres positifs en utilisant des additionneurs binaires.
Pas simple hein ? Bon je vais vous aider à retourner sur le chemin de la compréhension avec un exemple. Nous allons nous servir de la calculatrice que nous avons téléchargé tout à l'heure.
Ici j'ai pris une valeur au hasard 10110110 qui donne la valeur numérique 182. Tous les bits sont ensuite inversés et 1 est ajouté, nous avons donc ainsi la représentation en complément à deux de -182, 1001010. Nous additionnons ces deux valeurs ce qui donne 0 mais 256 est affiché car pcalc ne sait pas que nous manipulons des valeurs sur 8 bits.
Pour déclarer une variable non signée nous utilisons la syntaxe
unsigned int par exemple pour un entier non signé
Nous pouvons aussi augmenter ou diminuer la taille des variables numérique en utilisant long ou short. Le macro sizeof() donne la tailles de certains types de données, regardez :
Des variables magiques
Aussi et surtout appelé le forçage de type, c'est le fait de modifier temporairement (juste le temps d'une opération) le type d'une variable. Un entier int en nombre à virgule float par exemple. Regardez le programme ci-dessous :
Nous avons créés deux variables de type int et deux de type float. J'ai donné à la variable lvo un chiffre au hasard et à la variable abonnes le nombre de mes abonnes : 273. Nous divisons lvo par abonnes. Nous sommes censé obtenir 0,0329 mais nous obtenons après compilation :
Même si nous stockons notre résultat dans une variable de type float, la division nous donne un arrondie de réel résultat. Il faut donc forcer nos variables à ce mettre en float pour avoir le bon résultat. La syntaxe du forçage de type est donc :
(type) variable;
Ceci deviens réellement intéressant quand nous utilisons des pointeurs. En effet en C et comme dans de nombreu autres langages de programmation, un pointeur de type entier doit pointer uniquement vers des entiers et un pointeur de type caractère doit pointer uniquement vers des caractères.
C'est là qu'il va falloir s'accrocher un peu. Souvenez-vous bien que en entier occupe 4 octets et un caractère en occupe 1. Dans le programme suivant, nous allons créer deux tableaux. Un de type char qui va contenir des caractères et un autre de type int qui va contenir des entier. Nous allons ensuite créer deux pointeurs. Un de type char et un de type int. Nous allons placer le pointeur de type char au début du tableau du même type et de même pour le pointeur de type int. Enfin nous allons créer une boule for pour chaque tableaux. Pour les parcourir.
Ceci nous donne le résultat suivant après compilation :
Vous voyez que afin d'éviter des erreurs tels que
J'utilise les -Wall et -Wextra lors de la compilation. Ceci va me donner les erreurs ou les warning de mon programme. Ainsi, vous avez juste à chercher les erreurs sur Internet.
Revenons à nos moutons. On peut voir que le compilateur à incrémenté nos pointeurs de différentes façon alors qu'on avait dis d'incrémenter de 1 à chaque fois. C'est tout simplement dû au fait que l'entier prend 4 octets et le caractère seulement 1.
Maintenant changeons les règles. Au lieu de placer le pointeur int au début du tableau entier, plaçons le au début du tableau caractère. Faisons de même pour le pointeur char.
Le compilateur nous dis ici que le pointeur désigne un type de donnée incompatible. Il nous pose juste un warning mais ne stop pas pour autant la compilation en mettant une erreur. C'est un peu donc à nos risques et périls. Et puisque nous sommes curieux, regardons ce que ça peut bien donner :
Et oui, il se pose des erreurs d'affichage. Mais c'est tout à fait normal, un caractère prend un seul octet mais nous lui mettons un +4 à chaque tours de boucles. Un entier prend 4 octets mais nous lui mettons un +1 à chaque tours de boucles. Il est donc PRIMORDIAL que le pointeur pointe vers une donnée de même type que lui. C'est la que le forçage de type est bien pratique.
Ce code mérite quelques explications. Le (char *) tab_enti; et le (int *) tab_char; servent uniquement à forcer le type des données en celui des pointeurs afin de faire en sorte que le compilateur ne nous donne pas de warning. Puis il fallait aussi changer nos opérations sur nos pointeurs car elles restent encore fausses. Pour cela, lorsque nous ajoutons 1 aux pointeurs il faut forcer leur type pour les incrémenter de la bonne valeur puis il faut les reforcer dans leur type initial.
Mais pourquoi ne pas tout simplement utiliser le bon type de pointeur sur le bon type de pointeur
Haaa oui cela serait bien plus simple c'est vrai mais la vie n'est pas si simple. De temps en temps, nous avons besoin d'un pointeur qui n'a pas de type. Pour déclarer un pointeur sans type il faut le faire de la manière suivante :
void *votre_pointeur;
Prenons notre code précédent pour lui donner uniquement un pointeur sans type.
Et compilons ce programme :
Voilà ce qui clôture l'article de la semaine. Etant donné que ce n'était pas bien compliqué, je pense faire deux article le semaine prochaine, un le mercredi ou jeudi et un autre le dimanche. Dîtes moi ça en commentaire !
Hey ! J'éspère que cette série te plaîs ! N'hésite pas à me le dire en commentaire et aussi à me donner des conseils de rédaction, j'aime partager et apprendre des autres !
Top d'avoir ce type de contenu dense sur Steemit. :-)
Merci beaucoup ! J'essaie de passer le plus de temps possible à créer du bon contenu !
Bonne journée !