IPB

Bienvenue invité ( Connexion | Inscription )

 
Reply to this topicStart new topic
> Quelques bizzareries en C, Où le code ne fait pas ce qu'il suggère
Options
Jaypee
posté 19 Mar 2022, 19:58
Message #1


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Hello toutes et tous les codeurs en C,

J'ai vu passer un tweet provocateur sur le C, qui avait relaxé son typage à la manière de JavaScript.

Code
jaypee@MacMini2018JP LangageC % alias bat        
bat='gcc -w'
jaypee@MacMini2018JP LangageC % cat ./typesRelaches.c
#include <stdio.h>

int main() {
  puts("-0.5" + 1);
}

jaypee@MacMini2018JP LangageC % bat -o typesRelaches typesRelaches.c
jaypee@MacMini2018JP LangageC % ./typesRelaches                    
0.5


Puis il a eu dans le même relâchement des règles, l'adoption par C de l'exponentiation de Fortran, **:
Code
jaypee@MacMini2018JP LangageC % cat exposant.c
#include <stdio.h>
int main() {
  printf("%d\n", 50 **"2");
}
jaypee@MacMini2018JP LangageC % bat -o exposant exposant.c
jaypee@MacMini2018JP LangageC % ./exposant
2500


Enfin, on peut annoncer toujours dans cette même réforme du langage, un nouvel opérateur "tend vers" --> :
Code
jaypee@MacMini2018JP LangageC % cat tendVers.c    
#include <stdio.h>
int main() {
  int x = 5;
  while (x --> 0) {
    printf("%d ", x);
  }
  printf("\n");
}
jaypee@MacMini2018JP LangageC % bat -o tendVers tendVers.c
jaypee@MacMini2018JP LangageC % ./tendVers        
4 3 2 1 0


Mais, tout ça n'est en fait que fake news, Il y a une entourloupe, bien sûr ! Sauriez-vous rétablir la vérité ?

Crédits: la Twitteuse @lunasorcery

Ce message a été modifié par Jaypee - 19 Mar 2022, 20:01.
Go to the top of the page
 
+Quote Post
schlum
posté 19 Mar 2022, 23:33
Message #2


Terminaltor
Moderating Machine
*****

Groupe : Admin
Messages : 24 449
Inscrit : 25 Oct 2002
Lieu : Jeumont (59)
Membre no 4 319



Le premier affiche la chaine "-0.5" à partir du 2e caractère (addition à un pointeur)
Le deuxième déréférence la chaîne char* "2" (*"2" = '2' = 0x32 = 50)
La troisième c'est juste l'opérateur de décrément post-fixé (x-- = x-1)

^^


--------------------
          I think therefore I Mac          
Go to the top of the page
 
+Quote Post
Jaypee
posté 20 Mar 2022, 09:34
Message #3


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Bravo Schlum,

Mais je n'en attendais pas moins de la vielle garde :-)

On peut peut-être diluer un peu pour les débutants en C.

Leçon n°1, C se fiche de la présentation:
Code
int
x
=
5;
... est une instruction correcte en C.

Leçon n°2, un pointeur est un doublet (adresse, type)
L'incrémentation de 1 du pointeur donne pour résultat le pointeur (adresse + sizeof(type), type)
Dans ces exemples, il faut se rappeler qu'en C, il n'existe pas de type primitif "string", et on l'implémente par un pointeur sur caractère: char * text.
Dans les encodages occidentaux, en général, un caractère occupe un octet, et sa taille est 1.

Donc dans l'exemple n°1, on a une chaîne littérale (une valeur isolée, non attachée à un identificateur), comme 1, ou 0. Cette chaîne a néanmoins une certaine adresse, et "-0.5" + 1, ne fait qu'incrémenter de 1 l'adresse de la chaîne, c'est-à-dire, on saute le signe -. On utilise un "puts", car un "printf" aurait facilement trahi cette esbroufe. C'est aussi la raison de l'alias pour "gcc -w" qui " mange" tous les warnings qui auraient tout de suite donné l'alerte. Ne jamais compiler avec -w.

La leçon n°1 est applicable à l'exemple n°2 : on n'a pas d'opérateur **, mais une multiplication suivie de la déréférence d'un pointeur. La déréférence consiste à interpréter la mémoire à l'adresse du pointeur, en utilisant la taille du type, pour obtenir une valeur de ce type. * appliquée à un pointeur de caractère donne la valeur du caractère à cette adresse. Le chiffre 2, dans la table ASCII est à la position 50, et en C, caractère ou entier non-signé, c'est pareil. donc '2' == 50. Une manière simple de convertir un chiffre représenté en caractère, de '0' à '9', en sa valeur numérique est :
Code
int n;
char c;
c = '2';
n = c - '0'; // Note : '0' == 48
printf("%d\n", n);

Donc l'exemple n°2 calcule en fait 50 * 50.
Note : Si on déclare des structs avec des champs :
Code
struct personnage {
   int force;
   int age;
}

si on déclare un personnage directement, le point permet d'accéder au champ "age" :
Code
personnage merlin;
merlin.force = 1000;
merlin.age = 500;
int age = merlin.age;


et si on déclare un pointeur sur un personnage :
Code
personnage *pMagicien;
pMagicien = (personnage *)malloc(sizeof(personnage));

après qu'on a alloué la mémoire pour contenir les données, et qu'on a rempli la structure avec les données, on utilisera la flèche pour combiner * et .:
Code
pMagicien -> age = 200;
pMagicien -> force = 100;

Note plus avancée : Attention, il existe aussi la notion de handle, un pointeur sur un pointeur (de type adresse, taille selon la CPU), sur un type primitif ou défini dans les déclarations :
Code
Window **hWindow;


Leçon n°1 de nouveau, pour l'exemple n°3, --> n'existe pas comme opérateur. Avec des parenthèses supplémentaires, on aurait écrit:
Code
while((x--) > 0)


Un gros tampon [BUSTED] donc en travers de ces fake news !

JP

Ce message a été modifié par Jaypee - 24 Mar 2022, 07:55.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 23rd April 2024 - 17:19