Je ne comprends pas trop...

Je ne comprends pas trop... - C - Programmation

Marsh Posté le 06-07-2007 à 21:38:18    

Alors voilà, j'en suis au 1.6 du livre "le langage C, norme ANSI, 2nde édition" de K&R.
 
Et je ne comprends pas trop cette partie...
 
C'est "un programme qui compte les occurences des dix chiffres, des caractères d'espacement, et de tous les autres caractères".
 
Voici le code :
 

Code :
  1. #include <stdio.h>
  2. main ()
  3. {
  4. int c, i, nespace, nautre;
  5. int nchiffre[10];
  6. nespace = nautre = 0;
  7. for (i = 0; i < 10; ++i)
  8. nchiffre = 0;
  9. while ((c = getchar()) != EOF)
  10. if (c >= '0' && c <= '9')
  11. ++nchiffre[c-'0'];
  12. else if (c == ' ' || c == '\n' || c == '\t')
  13. ++nespace;
  14. else
  15. ++nautre;
  16. printf("chiffres =" );
  17. for (i = 0; i < 10; ++i)
  18. printf ("%d", nchiffre[i]);
  19. printf(", espacement = %d, autres = %d\n", nespace, nautre);
  20. }


 
1) Donc voilà, ce que je comprends tout d'abord, c'est le fonctionnement des tableau.
 
2) Ensuite, chose importante, je ne comprends pas ce que le programme nous donne en sortie à coté de "chiffres =".
En exemple du bouquin, ils disent :
[i]Appliqué à lui-même (c'est à dire au texte de la source)", ce programme donne
chiffres = 9 3 0 0 0 0 0 0 0 1, espacement = 159, autre = 403
"
D'où sortent ces chiffres? Le 9 n'est pas le 1er chiffre du code, et il n'y a pas de 3...Je ne comprends pas!
 
Merci pour votre aide.
 
P.S. Comme vous l'aurez remarqué, je débute en programmation, donc n'ayez pas peur de trop m'en expliquer (ou d'expliquer trop simplement)! :)


Message édité par floboss07 le 06-07-2007 à 21:41:23
Reply

Marsh Posté le 06-07-2007 à 21:38:18   

Reply

Marsh Posté le 06-07-2007 à 21:56:49    

comme je disais dans un autre topic, c'est un peu de l'éjaculation du cervellet ce truc.
 
ce qui m'inquiète, c'est que je le comprends :D
 
nchiffre est un array d'entiers de 10 lignes, allant de 0 à 9.
chaque ligne correspond au chiffre égal à l'index :
 
nchiffre[5] = nombre d'occurences du chiffre 5
 
++nchiffre[c-'0'] c'est le genre de truc qui me fait vomir (le top fun c'est que c'est un exemple d'un bouquin où "norme" est dans le tire :heink:)
 
'0' est le caractère ZERO. dans la table ASCII il a l'indice "chaispucombien". il est immédiatement suivit par les autres chiffres de 1 à 9... ca tombe bien c'est dans le même ordre que dans le tableau nchiffre !
 
mettons que '0' = 60 -d'après la table ascii que j'ai pas sous les yeux-
 
si je tapes 5 au clavier, la valeur de "c" est donc 65.
 
c-'0' = 5
je trouve donc mon chiffre.
 
d'où me "nchiffre[c-'0']" histoire dans notre exemple d'écrire à la ligne 5, c'est à dire la 6° ligne, qui contient les occurences du chiffre '5'
 
ensuite, on fait un ++ devant (pourquoi pas derrière ? certainement toujours pour rendre le code plus imbittable - en réalité une optimisation me dit-on dans le fond de la salle) qui permet d'incrémenter la valeur.
 
ainsi, si nchiffre[5] = 1 alors après le ++ il est égal à 2
 
ansi, d'après le résultat, tu as :
9 fois le chiffre ZERO
3 fois le chiffre UN
1 fois le chiffre NEUF
 
Ce qui semble juste :)

Message cité 2 fois
Message édité par MagicBuzz le 06-07-2007 à 21:58:55
Reply

Marsh Posté le 07-07-2007 à 12:06:14    

MagicBuzz a écrit :


++nchiffre[c-'0'] c'est le genre de truc qui me fait vomir (le top fun c'est que c'est un exemple d'un bouquin où "norme" est dans le tire :heink:)


 
C'est parfaitement suporté par la norme. char est un type entier sur lequel les opérations arithmétiques ont un sens.
 

MagicBuzz a écrit :


ensuite, on fait un ++ devant (pourquoi pas derrière ? certainement toujours pour rendre le code plus imbittable - en réalité une optimisation me dit-on dans le fond de la salle) qui permet d'incrémenter la valeur.


Si tu fais le ++ derriere tu stockerais 0 au lieu de 1 dans pour les chiffres n'ayant qu'une occurence

Reply

Marsh Posté le 07-07-2007 à 12:46:07    

Joel F a écrit :

C'est parfaitement suporté par la norme. char est un type entier sur lequel les opérations arithmétiques ont un sens.


je ne dis pas que c'est pas supporté par la norme.
je dis que l'écriture est horrible.
respecter les normes, c'est avant tout améliorer la lisibilité du code et améliorer sa maintenabilité, ce qui est loin d'être le cas avec ce type d'écriture. (à la base, respecter une norme, c'est avant tout garantir que n'importe qui peut repasser derrière soit sans perdre un temps précieux à comprendre ce qu'on a voulu faire et qui ne marche pas)
 
la norme pose des règles du jeu, offre des possibilités, mais vient aussi avec un certain nombre de notions de sémantique et d'état d'esprit. respecter les deux premiers est loin d'être suffisant.
 
c'est un peu comme la norme XHTML : c'est pas parceque le code passe au validateur XHTML sans erreurs qu'il est compatible avec la norme.
 

Joel F a écrit :

Si tu fais le ++ derriere tu stockerais 0 au lieu de 1 dans pour les chiffres n'ayant qu'une occurence


comment ça ?
 
nchiffre[c-'0']++ ça va me faire rigoureusement la même chose que ++nchiffre[c-'0'] !
 
le seul cas où ça change c'est si je fais ça :
 
a = nchiffre[c-'0']++ => là effectivement, à la sortir de la ligne, a n'est pas égal à nchiffre[c-'0'] puisque l'incrémentation s'est faite après.
 
++nchiffre[c-'0']; ça revient à :
 
nchiffre[c-'0'] += 1;
a = nchiffre[c-'0'];
 
alors que a = nchiffre[c-'0']++; revient à :
 
a = nchiffre[c-'0'];
nchiffre[c-'0'] += 1;
 
mais dans le cas où on n'affecte le résultat du ++ null part, ça change rien à son fonctionnement.
m'enfin après, y'a peut-être des gens qui trouvent ça plus lisible de mettre le ++ devant, mais pas moi :spamafote:
 
dans tous les cas, on est ici au 6° sous-chapitre du premier chapitre d'un bouquin, je trouve quand même que :
 
nchiffre[asc(c) - asc('0')] += 1;
 
est bien plus lisible, notamment parceque le néofite comprend ce que fait le code. évidement, on vient de multiplier inutilement la durée du traitement par 3, je suis bien d'accord. mais à mon avis à ce pointdu bouquin, vu l'exemple, on est encore loin de se poser des questions métaphysiques à propos de l'optimisation, mais plutôt en train d'expliquer les bases.
 
ps : j'utilise "asc()" ici, en fait je sais pas comment s'appelle cette fonction, qui pemet de récupérer le code ascii d'un char)
et tu dis que '0' est de type int (donc 32 bits)... il est pas plutôt sur 8 bits dont le bit de poids fort inutilisable ?

Message cité 5 fois
Message édité par MagicBuzz le 07-07-2007 à 12:56:43
Reply

Marsh Posté le 07-07-2007 à 15:52:13    

MagicBuzz a écrit :


respecter les normes, c'est avant tout améliorer la lisibilité du code et améliorer sa maintenabilité, ce qui est loin d'être le cas avec ce type d'écriture. (à la base, respecter une norme, c'est avant tout garantir que n'importe qui peut repasser derrière soit sans perdre un temps précieux à comprendre ce qu'on a voulu faire et qui ne marche pas)

 

la norme pose des règles du jeu, offre des possibilités, mais vient aussi avec un certain nombre de notions de sémantique et d'état d'esprit. respecter les deux premiers est loin d'être suffisant.

 

c'est un peu comme la norme XHTML : c'est pas parceque le code passe au validateur XHTML sans erreurs qu'il est compatible avec la norme.


Euh, absolument pas. Respecter la norme c'est respecter la norme c'est tout, et l'objectif d'une norme comme celle du C est d'établir un contrat entre le développeur et le compilateur. Ce contrat dit juste que si ton compilateur respecte le norme, tant que toi aussi tu respecte la norme tu est sûr d'obtenir le comportement définit par celle-ci.

 

La problématique de maintenabilité, de lisibilité de code et de coopération entre utilisateurs n'a rien à voir avec la norme du C.

MagicBuzz a écrit :


dans tous les cas, on est ici au 6° sous-chapitre du premier chapitre d'un bouquin, je trouve quand même que :

 

nchiffre[asc(c) - asc('0')] += 1;

 

est bien plus lisible, notamment parceque le néofite comprend ce que fait le code. évidement, on vient de multiplier inutilement la durée du traitement par 3, je suis bien d'accord. mais à mon avis à ce pointdu bouquin, vu l'exemple, on est encore loin de se poser des questions métaphysiques à propos de l'optimisation, mais plutôt en train d'expliquer les bases.

 

ps : j'utilise "asc()" ici, en fait je sais pas comment s'appelle cette fonction, qui pemet de récupérer le code ascii d'un char)
et tu dis que '0' est de type int (donc 32 bits)... il est pas plutôt sur 8 bits dont le bit de poids fort inutilisable ?


Encore un cas où tu parle sans connaitre le language.
'0' est de type int et a pour valeur le code ascii du char, tu peut ajouter un asc() autour si t'as vraiment envie mais ta fonction ne fera absolument rien.
M'enfin c'est vrai que la ligne est vachement plus claire, maintenant que t'en a triplé la longueur, mais c'est un exercice venant du K&R, pas d'un tutoriel C pour les codeurs Java, on a le droit de faire des lignes de moins de 80 caractères :o


Message édité par 0x90 le 07-07-2007 à 16:05:31

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 07-07-2007 à 16:31:44    

MagicBuzz a écrit :

m'enfin après, y'a peut-être des gens qui trouvent ça plus lisible de mettre le ++ devant, mais pas moi :spamafote:


 
Pas tout à fait. En fait, faire "++i" est plus rapide que de faire "i++". Parce que, dans la seconde écriture, tu dois d'abord définir une zone de stockage temporaire pour i avant de l'incrémenter puis renvoyer la valeur de la zone temporaire (amuse-toi donc à redéfinir l'opérateur ++ en pré et post incrémentation en C++ et tu comprendras).
Donc certains programmeurs, conscients de la chose, préfèrent écrire "++truc" plutôt que "truc++". Ce n'est pas mon cas qui préfère autant que possible écrire "truc++" mais chacun est libre de ses préférences...
 

MagicBuzz a écrit :

je ne dis pas que c'est pas supporté par la norme, je dis que l'écriture est horrible.


Chacun ses goûts...
 

MagicBuzz a écrit :

respecter les normes, c'est avant tout améliorer la lisibilité du code et améliorer sa maintenabilité, ce qui est loin d'être le cas avec ce type d'écriture. (à la base, respecter une norme, c'est avant tout garantir que n'importe qui peut repasser derrière soit sans perdre un temps précieux à comprendre ce qu'on a voulu faire et qui ne marche pas)


N'importe qui qui a un peu plus de 2 jours de prog C est capable de lire avec aisance la notation 'x' symbolisant la notation "code ascii"...
 

MagicBuzz a écrit :

dans tous les cas, on est ici au 6° sous-chapitre du premier chapitre d'un bouquin, je trouve quand même que :
 
nchiffre[asc(c) - asc('0')] += 1;
 
est bien plus lisible, notamment parceque le néofite comprend ce que fait le code.


Encore une fois, il y a néophyte et néophyte. Il y a le néophyte faignasse qui prend un bouquin de C au hasard parmi tous les bouquins de C pouvant exister et tombant parfois sur un bouquin écrit par un type ne pipant rien au C mais qui voulait se donner un genre, qui l'ouvre au milieu du chapitre 42 et qui dit "oh putain je comprends rien, le C c'est vraiment un langage de merde" et il y a le néophyte volontaire qui commence par chercher un bouquin de C de valeur, qui l'ouvre ensuite à la première page du premier chapitre et qui commence à lire...

Message cité 1 fois
Message édité par Sve@r le 07-07-2007 à 16:45:07

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-07-2007 à 16:39:31    

Sve@r a écrit :

Pas tout à fait. En fait, faire "++i" est plus rapide que de faire "i++". Parce que, dans la seconde écriture, tu dois d'abord définir une zone de stockage temporaire pour i avant de l'incrémenter puis renvoyer la valeur de la zone temporaire (amuse-toi donc à redéfinir l'opérateur ++ en pré et post incrémentation en C++ et tu comprendras).


C'est la cat C ici, et meme si c'etait du C++, ++i ou i++ sur un int je doute fort que ca fasse une difference...  

Reply

Marsh Posté le 07-07-2007 à 16:46:03    

MagicBuzz a écrit :


je ne dis pas que c'est pas supporté par la norme. je dis que l'écriture est horrible.
respecter les normes, c'est avant tout améliorer la lisibilité du code et améliorer sa maintenabilité, ce qui est loin d'être le cas avec ce type d'écriture. (à la base, respecter une norme, c'est avant tout garantir que n'importe qui peut repasser derrière soit sans perdre un temps précieux à comprendre ce qu'on a voulu faire et qui ne marche pas)
 
la norme pose des règles du jeu, offre des possibilités, mais vient aussi avec un certain nombre de notions de sémantique et d'état d'esprit. respecter les deux premiers est loin d'être suffisant.


oui mais non  [:everything4free] la norme est la norme est la norme. Faut pas confondre norme et guide de style. La norme dit : "'0' est de type int" donc je le manipule comme un int point. :o
 

MagicBuzz a écrit :


comment ça ?


J'avais mal lu :o
 
 

MagicBuzz a écrit :


est bien plus lisible, notamment parceque le néofite comprend ce que fait le code. évidement, on vient de multiplier inutilement la durée du traitement par 3, je suis bien d'accord. mais à mon avis à ce pointdu bouquin, vu l'exemple, on est encore loin de se poser des questions métaphysiques à propos de l'optimisation, mais plutôt en train d'expliquer les bases.


Sauf que bon, le chapitre d'avant a expliqué ++ donc bon  :sarcastic:  
 

MagicBuzz a écrit :


et tu dis que '0' est de type int (donc 32 bits)... il est pas plutôt sur 8 bits dont le bit de poids fort inutilisable ?


En C tout les types entiers (char,short,int) sont auto-promu en int lors des opérations arithmétiques.

Reply

Marsh Posté le 07-07-2007 à 16:49:22    

Ace17 a écrit :

C'est la cat C ici


Je parlais du C++ à titre uniquement illustratif car ce langage permet de redéfinir des opérateurs et permet donc de mieux comprendre les raisons de certains comportements du C mais la techno reste valable en C. Et que cela fasse une grande différence ou pas sur un int importe peu puisque je parle ici de préférences personnelles de certains et d'autres...


Message édité par Sve@r le 07-07-2007 à 16:56:15

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 07-07-2007 à 23:17:37    

'tain mais Magic, t'en rates vraiment pas une ...
comme dis dès le début, les char sont des entiers, mais pires, '0' est de type int.

Reply

Marsh Posté le 07-07-2007 à 23:17:37   

Reply

Marsh Posté le 08-07-2007 à 01:31:57    

Taz a écrit :

'tain mais Magic, t'en rates vraiment pas une ...
comme dis dès le début, les char sont des entiers, mais pires, '0' est de type int.


Nan, et Joel F donne la bonne réponse.
 
Les types entiers sont auto-promu en int lors de calculs arithmétiques. et heureusement encore que char c'est pas un int... ca me ferait bien mal de voir le C occuper 4 fois plus de mémoire que nécessaire pour stocker des chaînes de caractères.
 
Enfin, moi je ne repproche pas le fait que '0' soit assimilable à un entier en C, réveillez-vous les gars, c'est pas le seul langage qui l'accepte.
 
Mais si ça vous fait bander de voir des calculs entiers sur des caractères dans un bouquin, tant mieux pour vous. Moi j'aime pas ça, et je vois pas ce qu'il y a de condamnable là dedans.
Et arrêtez de me dire que c'est limpide, sinon floboss07 n'aurait pas demandé d'explications vu qu'il a déjà lu tous les autres chapitres avant.
 
D'ailleurs, je tiens à remercier cette enflure de se pointer, et pas dire un merci ni merde après mon explication, puis se tirer quand j'ai tous les Trolls de la cat C sur le dos.
 
En attendans, au lieu de venir m'emmerder à Troller comme des commères autour derrière leur carreaux, le prochain coup vous expliquerez le code quand une personne posera une question, ça m'évitera de parler de choses que je ne connais pas, et ça vous évitera de gaspiller votre salive en sarcasmes aussi puérils que pathétiques.
 
(pourtant pas bu de café moi ça de soir :??:)

Reply

Marsh Posté le 08-07-2007 à 05:17:04    

Ace17 a écrit :

C'est la cat C ici, et meme si c'etait du C++, ++i ou i++ sur un int je doute fort que ca fasse une difference...


 
En fait, ca ne fait un difference que si tu utilise le resultat, sinon ton compilo a vite faire de remettre ca dans le bon sens pour peut que tu ais mis les option d'optimisation du compilo.
 
MagicBuzz > Les variables du programme sont toujours codées sur 32 ou 64 bits. C'est une question d'architecture processeur., ou tu peut charger la valeur direct dans un registre (et dans ce cas elle fait la taille du registre) ou bien tu la stoque en memoire dans le code du programme, et a ce moment la, pour pas decaler toutes tes instructions et que tu puisse les chopper en un acces memoire (sinon tu divise par deux la vitesse de ton pc), tu les alignes.
 
Dans tous les cas, une valeur en dur dans ton code est sur 32 ou 64 bits en fonction de ton architecture. C'est d'ailleur specifiée dans les normes. Ca n'est aps le cas pour un chaine de caracteres (gaspillage memoire) mais c'est le cas pour '0' qui est une valeur en dur.

Reply

Marsh Posté le 08-07-2007 à 10:13:40    

Passez a un langage correctement typé comme Ocaml et laissez le Fortran C crever en paix  :o  :jap:  
 

Spoiler :

[:cupra]

Reply

Marsh Posté le 08-07-2007 à 10:23:08    

yk42b a écrit :

Passez a un langage correctement typé comme Ocaml et laissez le Fortran C crever en paix  :o  :jap:  
 

Spoiler :

[:cupra]



 
Mon trollometre s'affole  :sol:  [:joel f]

Reply

Marsh Posté le 08-07-2007 à 11:45:28    

deadalnix a écrit :

MagicBuzz > Les variables du programme sont toujours codées sur 32 ou 64 bits. C'est une question d'architecture processeur., ou tu peut charger la valeur direct dans un registre (et dans ce cas elle fait la taille du registre) ou bien tu la stoque en memoire dans le code du programme, et a ce moment la, pour pas decaler toutes tes instructions et que tu puisse les chopper en un acces memoire (sinon tu divise par deux la vitesse de ton pc), tu les alignes.


Oui oui, je vois parfaitement. J'ai fais un peu d'ASM quand j'étais étudiant, donc je vois parfaitement la raison du pourquoi du comment.
 
Par contre, ton truc m'inquiète...
 
Ca veut dire que ci j'ai ça :
 
char c;
c = 127;
 
c++;
 
=> c est égal à 128 ??
 
c++ *= 2;  
 
=> c est égal à 257 ?? sans broncher ??
 
si je recolle ensuite mon char dans une chaîne de caractères, il se passe quoi ? il garde cette représentation sur 16 bits ? un modulo 128 est effectué ?
 
ça me fait un peu peur quand même... y'a aucun contrôle effectué par le compilateur ? :sweat:
 
un char étant codé sur 7 bits, autant je comprends qui prenne la taille d'un registre entier du processeur pour faire les calculs (ceci dit, les registes 16 bits existent encore si je ne m'abuse, pourquoi ne pas faire les calculs dedans ?), autant j'ai du mal à imaginer que le compilo laisse écrire des valeurs sur 32 (ou 64) bits dedans... il se passe quoi à ce moment ? exception (ce qui me semble normal), simple troncage (moyen mais c'est toujours ça) ou carrément aucun contrôle (impossible de prévoir à l'avance le comportement du programme) ?

Message cité 4 fois
Message édité par MagicBuzz le 08-07-2007 à 12:08:02
Reply

Marsh Posté le 08-07-2007 à 12:06:29    

deadalnix a écrit :

En fait, ca ne fait un difference que si tu utilise le resultat, sinon ton compilo a vite faire de remettre ca dans le bon sens pour peut que tu ais mis les option d'optimisation du compilo.

En C, ok. En C++, ca m'etonnerait vraiment beaucoup que le compilo puisse se permettre de choisir entre post et pre incrementation. Or c'est precisement a ce moment que ca aurait fait une difference de performance.

Reply

Marsh Posté le 08-07-2007 à 13:40:50    

MagicBuzz a écrit :


Par contre, ton truc m'inquiète...

 

Il faut pas oublier que le C reste juste de l'assembleur humainement lisible aussi.
et bon tu te saurais sorti les doigts pour chauffer ton gcc ...

 
Code :
  1. #include <stdio.h>
  2. int main(int,char**)
  3. {
  4.   char c = 127;
  5.   printf("%x --> %d\n",c,c);
  6.   printf("%x --> %d\n",c+1,c+1);
  7.  
  8.   c++;
  9.   printf("%x --> %d\n",c,c);
  10.  
  11.   c *= 2;
  12.   printf("%x --> %d\n",c,c);
  13. return 0;
  14. }
 

renvoie la chose suivante :

 
Code :
  1. 127
  2. -128
  3. 0
 

Je passe sur c = 127 :o

 

c++    -> auto-promotion : c = int(c) + 1 = 128 = 0x00000080 -> troncature sur 8 bits c = 0x80 = -128
c *=2 -> idem  c = int(c) * 2 -> -128 = 0xFFFFFF80 -> -128 * 2 = 0xFFFFFF00 -> troncature c = 0x00 = 0

 

et sans vouloir m'avancer, ca doit etre dans la norme ce genre de comportement

Message cité 1 fois
Message édité par Joel F le 08-07-2007 à 15:51:05
Reply

Marsh Posté le 08-07-2007 à 15:31:46    

MagicBuzz a écrit :

Nan, et Joel F donne la bonne réponse.
 
Les types entiers sont auto-promu en int lors de calculs arithmétiques. et heureusement encore que char c'est pas un int... ca me ferait bien mal de voir le C occuper 4 fois plus de mémoire que nécessaire pour stocker des chaînes de caractères.


 
T'en rates pas une, les 2 sont vrais sauf que t'es pas foutu de faire la différence entre char et '0'.
 
- les char sont un type entier, comme les int, et sont promus lors des calculs
- '0' (c'est à dire les caractères ' puis 0 puis ' dans un fichier source de C et une fois parsés par le compilateur ) est bien de type int et non de type char
 
ET si t'es pas d'accord et que tu te sens encore de faire un paté de 20 lignes en déviant un poil la question systématiquement et en parlant de choses que encore une fois tu ne connais pas. VA LIRE CETTE PUTAIN DE NORME (chapitre 6.4.4.4 paragraphes 2 et 10 principalement ).


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 08-07-2007 à 16:23:29    

MagicBuzz a écrit :

Mais si ça vous fait bander de voir des calculs entiers sur des caractères dans un bouquin, tant mieux pour vous. Moi j'aime pas ça, et je vois pas ce qu'il y a de condamnable là dedans.


Absolument rien... tant que tu ne viens pas affirmer ensuite de façon péremptoire "cette écriture-ci est incompréhensible, il faut utiliser celle-là".
 

MagicBuzz a écrit :

ça me fait un peu peur quand même... y'a aucun contrôle effectué par le compilateur ? :sweat:


Hé non. Philosophie du langage => le programmeur sait ce qu'il fait
 

MagicBuzz a écrit :

un char étant codé sur 7 bits, autant je comprends qui prenne la taille d'un registre entier du processeur pour faire les calculs (ceci dit, les registes 16 bits existent encore si je ne m'abuse, pourquoi ne pas faire les calculs dedans ?), autant j'ai du mal à imaginer que le compilo laisse écrire des valeurs sur 32 (ou 64) bits dedans... il se passe quoi à ce moment ? exception (ce qui me semble normal), simple troncage (moyen mais c'est toujours ça) ou carrément aucun contrôle (impossible de prévoir à l'avance le comportement du programme) ?


Mais si on peut prévoir... quand on connait la règle: Dans une expression arithmétique, l'expression est intégralement calculée dans le type le plus large de tous les opérandes présents. Ensuite, si le résultat doit être stocké dans un type plus étroit, il y a simplement troncature (et non troncage). Ainsi, si j'écris 'a' * 3.1416, j'aurai comme résultat 304.7352 ce qui n'a absolument rien d'étonnant pour celui qui y est habitué (évidemment m'a fallu quand-même aller voir la valeur de 'a' avant d'écrire le résultat mais c'est juste pour illustrer). Ensuite, tout dépend de la variable qui recevra ce 304.7352.
Evidemment je vois mal la raison qui pourrait me faire multiplier 'a' par pi mais si je veux juste connaître l'écart qu'il y a entre 'e' et 'q', je taperai simplement 'q' - 'e' sans me poser de questions métaphysiques sur ce style d'écriture...

Message cité 1 fois
Message édité par Sve@r le 08-07-2007 à 19:03:45

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 08-07-2007 à 18:48:59    

MagicBuzz a écrit :

Par contre, ton truc m'inquiète...
 
Ca veut dire que ci j'ai ça :
 
char c;
c = 127;
 
c++;
 
=> c est égal à 128 ??


 
En fait non ca ne se pase pas comme ca. Si ta variable 127 est bien codée sur 32bits dans le code compilé, elle va etre tronquée pour ne garder que les bits de poid faible et stoquée dans c.
 
Ca sera donc egal a -128 comme je sait plus qui l'as dit Joel F. et effectivement c'est dans la norme tous ces comportements.
 
Dans 99% des cas c'est transparent pour toi cette cuisine et tu n'as pas a t'en occuper. Mais dans quelques tres rares cas particulier ca peut faire une difference. Si c'est le cas, on peut plus penser a un probleme de conception, car ca veux dire que ton programme compilera pas en 64bit par exemple si tu passes de 32 a 64 bits.
 
Juste qu'il faut garder en tete que '0' est un entier codé sur 32 ou 64 bits.

Reply

Marsh Posté le 08-07-2007 à 19:32:37    

MagicBuzz a écrit :

'0' est le caractère ZERO.


 
'0' est une constante entière qui a pour valeur le code du caractère 0 dans le jeu de caractère utilisé, que ce soit ASCII, EBCDIC ou autre chose.  Je doute en fait que ce soit l'un de ces deux là, le plus vraissemblable est un extension sur 8 bits de l'ASCII.
 

Citation :

il est immédiatement suivit par les autres chiffres de 1 à 9...


 
C'est une des rares contraintes sur les jeux de caractères qui peuvent être utilisé en C.  (Les lettres elles ne doivent pas être consécutives.)

Reply

Marsh Posté le 08-07-2007 à 19:52:24    

MagicBuzz a écrit :

je dis que l'écriture est horrible.


 
C'est du C très idiomatique.
 

Citation :

la norme pose des règles du jeu, offre des possibilités, mais vient aussi avec un certain nombre de notions de sémantique et d'état d'esprit. respecter les deux premiers est loin d'être suffisant.


 
C'est tout à fait dans l'état d'esprit du C.
 

Citation :

ps : j'utilise "asc()" ici, en fait je sais pas comment s'appelle cette fonction, qui pemet de récupérer le code ascii d'un char)


 
Il n'y a pas de telle fonction.  Les char sont un type entiers.  Les constantes de caractères sont de types int (au contraire du C++ où elles sont de type char).

Reply

Marsh Posté le 08-07-2007 à 19:56:38    

MagicBuzz a écrit :

Enfin, moi je ne repproche pas le fait que '0' soit assimilable à un entier en C, réveillez-vous les gars, c'est pas le seul langage qui l'accepte.


 
Même Wirth y est arrivé (Obéron)
 

Citation :

Mais si ça vous fait bander de voir des calculs entiers sur des caractères dans un bouquin, tant mieux pour vous. Moi j'aime pas ça, et je vois pas ce qu'il y a de condamnable là dedans.


 
Tu peux ne pas aimer (moi non plus), mais c'est dans l'esprit du C.

Reply

Marsh Posté le 08-07-2007 à 20:37:03    

deadalnix a écrit :

MagicBuzz > Les variables du programme sont toujours codées sur 32 ou 64 bits.


 
Mais non.
 

Citation :

Dans tous les cas, une valeur en dur dans ton code est sur 32 ou 64 bits en fonction de ton architecture.


 
Sur x86, on a sans problèmes des valeurs en dur sur 8 bits.
 

Citation :

C'est d'ailleur specifiée dans les normes.


 
Références?
 

MagicBuzz a écrit :

Ca veut dire que ci j'ai ça :
 
char c;
c = 127;
 
c++;
 
=> c est égal à 128 ??


Si char est non signé ou fait plus de 8 bits, oui.  S'il est signé et fait 8 bits, tu as un comportement indéfini (le plus vraissemblable étant que c vaille -128).
 

Citation :

c++ *= 2;


 
Ca ne devrait pas compiler (ni en C, ni en C++; en C++ ++c*= 2 compile mais est un comportement indéfini).
 

Citation :

ça me fait un peu peur quand même... y'a aucun contrôle effectué par le compilateur ? :sweat:


 
On parle du C ici  ;)  
 

Citation :

un char étant codé sur 7 bits,


 
En C, un char fait au moins 8 bits.
 

Citation :

autant je comprends qui prenne la taille d'un registre entier du processeur pour faire les calculs (ceci dit, les registes 16 bits existent encore si je ne m'abuse, pourquoi ne pas faire les calculs dedans ?),


 
Pas sur toutes les architectures.
 

Citation :

autant j'ai du mal à imaginer que le compilo laisse écrire des valeurs sur 32 (ou 64) bits dedans... il se passe quoi à ce moment ? exception (ce qui me semble normal), simple troncage (moyen mais c'est toujours ça) ou carrément aucun contrôle (impossible de prévoir à l'avance le comportement du programme) ?


 
Ca dépend du processeur.  La troncature est le comportement le plus fréquent.
 

Sve@r a écrit :

Mais si on peut prévoir... quand on connait la règle: Dans une expression arithmétique, l'expression est intégralement calculée dans le type le plus large de tous les opérandes présents.


Vrai pour chaque opération individuellement, mais pas pour l'ensemble de l'expression.  Par exemple, dans
 
1.5 + 1 / 2
 
1/2 est calculé en entier, pas en flottant.
 

Citation :

Ensuite, si le résultat doit être stocké dans un type plus étroit, il y a simplement troncature (et non troncage).


 
Pas tout à fait vrai. Si la destination est
- un type entier non signé, la valeur est ramenée dans l'intervalle représentable par addition/soustraction d'un de plus que la valeur maximale représentable (en représentation complément à deux c'est bien une troncature, dans les autres représentation, c'est autre chose)
- pour les types entiers signés, c'est un comportement spécifié par l'implémentation (soit une valeur, soit un signal)
- si la valeur est flottante, elle est d'abord ramenée en entier par troncature

Reply

Marsh Posté le 08-07-2007 à 21:33:21    

Un Programmeur a écrit :


Ca ne devrait pas compiler (ni en C, ni en C++; en C++ ++c*= 2 compile mais est un comportement indéfini).


 
Tout les bon crémier répondent ici : Non lvalue in assignement

Reply

Marsh Posté le 09-07-2007 à 00:32:29    

MagicBuzz a écrit :

Nan, et Joel F donne la bonne réponse.
 
Les types entiers sont auto-promu en int lors de calculs arithmétiques. et heureusement encore que char c'est pas un int... ca me ferait bien mal de voir le C occuper 4 fois plus de mémoire que nécessaire pour stocker des chaînes de caractères.
 
Enfin, moi je ne repproche pas le fait que '0' soit assimilable à un entier en C, réveillez-vous les gars, c'est pas le seul langage qui l'accepte.

Je vais pas répondre à tout le topic au sujet de 'toi vs. tous les autres' mais personne n'assimile rien '0' est un int, et les char sont des entiers. Après si t'as du mal avec la sémantique ...
Tout le monde s'en fiche bien de ce que tu aimes, on est là pour utiliser un outil.

Reply

Marsh Posté le 09-07-2007 à 00:33:25    

Joel F a écrit :

Il faut pas oublier que le C reste juste de l'assembleur humainement lisible aussi.  
et bon tu te saurais sorti les doigts pour chauffer ton gcc ...
 

Code :
  1. #include <stdio.h>
  2. int main(int,char**)
  3. {
  4.   char c = 127;
  5.   printf("%x --> %d\n",c,c);
  6.   printf("%x --> %d\n",c+1,c+1);
  7.  
  8.   c++;
  9.   printf("%x --> %d\n",c,c);
  10.  
  11.   c *= 2;
  12.   printf("%x --> %d\n",c,c);
  13. return 0;
  14. }


 
renvoie la chose suivante :
 

Code :
  1. 127
  2. -128
  3. 0



Avec gcc, du complément à 2 et des char sur 8 bits, oui :)

Reply

Marsh Posté le 09-07-2007 à 00:35:12    

deadalnix a écrit :

En fait non ca ne se pase pas comme ca. Si ta variable 127 est bien codée sur 32bits dans le code compilé, elle va etre tronquée pour ne garder que les bits de poid faible et stoquée dans c.

 

Ca sera donc egal a -128 comme je sait plus qui l'as dit Joel F. et effectivement c'est dans la norme tous ces comportements.

 

Dans 99% des cas c'est transparent pour toi cette cuisine et tu n'as pas a t'en occuper. Mais dans quelques tres rares cas particulier ca peut faire une difference. Si c'est le cas, on peut plus penser a un probleme de conception, car ca veux dire que ton programme compilera pas en 64bit par exemple si tu passes de 32 a 64 bits.

 

Juste qu'il faut garder en tete que '0' est un entier codé sur 32 ou 64 bits.

ça n'est pas dans la norme que CHAR_MAX + 1 == -128. Je zap sur toutes les bêtises de 32 ou 64bits

 

EDIT: et je ferme ma gueule, plein de personnes sympathiques ont déjà très bien répondu :)


Message édité par Taz le 09-07-2007 à 00:36:38
Reply

Marsh Posté le 09-07-2007 à 01:45:50    

Un Programmeur a écrit :

Sur x86, on a sans problèmes des valeurs en dur sur 8 bits.


 
Oui et elle decale ensuit tout les valeurs dans ton code, resultat, deux cycles pour faire chaque acces memoire. Bien sur on peut, mais c'est completement con, et le compilo le fera jamais.
 
Taz > j'ai parlé de 32 ou 64 bit car c'est probablement ce que tu as sous ton bureau en ce moment, c'est pareil , faut pas etre idiot.
 
CHAR_MAX + 1 == CHAR_MIN pas -128. Dans la pratique ca revient au meme. Les entiers bouclent c'est un comportement connus (ou qui du moins devrait l'etre).
 
Cela dit quand on dit rien on dit pas de conneries hein ;)
 
Par contre pour les variables dans le programme, dsl, abus de langage je voulais dire les valeurs en dur.

Message cité 1 fois
Message édité par deadalnix le 09-07-2007 à 01:47:17
Reply

Marsh Posté le 09-07-2007 à 01:46:53    

...


Message édité par deadalnix le 09-07-2007 à 01:47:34
Reply

Marsh Posté le 09-07-2007 à 09:05:09    

deadalnix a écrit :

Oui et elle decale ensuit tout les valeurs dans ton code, resultat, deux cycles pour faire chaque acces memoire. Bien sur on peut, mais c'est completement con, et le compilo le fera jamais.


 
En deassemblant le resultat de la compilation de

Code :
  1. #include <stdio.h>
  2. void foo(char c) {
  3.     if (c == 'a') {
  4.         puts("a" );
  5.     } else {
  6.         puts("b" );
  7.     }
  8. }

j'ai:

00000000 <foo>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   80 7d 08 61             cmpb   $0x61,0x8(%ebp)
   7:   74 0f                   je     18 <foo+0x18>
   9:   c7 45 08 00 00 00 00    movl   $0x0,0x8(%ebp)
  10:   c9                      leave  
  11:   e9 fc ff ff ff          jmp    12 <foo+0x12>
  16:   89 f6                   mov    %esi,%esi
  18:   c7 45 08 02 00 00 00    movl   $0x2,0x8(%ebp)
  1f:   eb ef                   jmp    10 <foo+0x10>

Tu remarqueras

  • que le compilateur a utilise des constantes sur 8 bits (0x61)
  • que l'encodage des instructions est tres irregulier


Citation :

CHAR_MAX + 1 == CHAR_MIN pas -128. Dans la pratique ca revient au meme. Les entiers bouclent c'est un comportement connus (ou qui du moins devrait l'etre).


CHAR_MAX+1 n'est garanti etre CHAR_MIN que si char n'est pas signe, donc que CHAR_MIN vaut 0.

Reply

Marsh Posté le 09-07-2007 à 15:36:40    

MagicBuzz a écrit :


[...]
Et arrêtez de me dire que c'est limpide, sinon floboss07 n'aurait pas demandé d'explications vu qu'il a déjà lu tous les autres chapitres avant.
 
D'ailleurs, je tiens à remercier cette enflure de se pointer, et pas dire un merci ni merde après mon explication, puis se tirer quand j'ai tous les Trolls de la cat C sur le dos.
 
En attendans, au lieu de venir m'emmerder à Troller comme des commères autour derrière leur carreaux, le prochain coup vous expliquerez le code quand une personne posera une question, ça m'évitera de parler de choses que je ne connais pas, et ça vous évitera de gaspiller votre salive en sarcasmes aussi puérils que pathétiques.
 
(pourtant pas bu de café moi ça de soir :??:)


 
L'enflure t'aurais bien remercié, mais ton message sympatique m'ayant beaucoup touché, j'en ai plus trop envi...  :na:  
 
En tout cas désolé mais j'avais pas eu le temps ces temps ci, et d'ailleur je viens de voir tout le bruit qu'a fait ma pauvre petite question (enfin surtout ta réponse en fait...! lol), quelle surprise! lol
 
Mais malgrès tout ça, j'ai compris! Je vais pouvoir passer à la suite! ^^
 
Ah et pour info, voici l'introduction sur le chapitre premier :
 
Commençons par une rapide introduction au langage C. Notre but est d'exposer les principes fondamentaux de ce langage à l'aide de véritables programmes, sans nous enliser pour autant dans un fouillis de détails, de règles et d'exeptions. A ce stade, nous ne cherchons pas à être complets, ni même précis (toutefois, les exemples sont censés être justes). Nous voulons que vous arriviez le plus vite possible à écrire des programmes utiles, et pour cela, il faut que nous insistions sur les bases : les variables et les constantes, les calculs, les structures de contrôle, les fonctions et quelques rudiments d'entrées-sorties. Dans ce chapitre, nous laissons volontairement des pointeurs, des structures, de la plupart des nombreux opérateurs du C, de diverses instructions de contrôle, et de la bibliothèque standard.
Une approche n'est pas exempte de défauts. En particulier, on ne trouvera pas ici toutes les explications sur un point de vue quelconque du langage, et cette initiation peut également être trompeuse par sa brièveté. De plus, comme les exemples n'utilisent pas toute la puissance du C, ils pourraient être plus concis et plus élégants. Nous avons tenté de minimiser les effets de cette simplification, mais soyez-en conscient.
[...]

Reply

Marsh Posté le 09-07-2007 à 17:29:10    

Ah ben voilà, si le bouquin prévient, effectivement on comprend mieux pkoi dès le début c'est imbittable :D
 
M'enfin bon, t'as compris, c'est le principal.

Reply

Marsh Posté le 09-07-2007 à 18:43:25    

Un Programmeur a écrit :

En deassemblant le resultat de la compilation de

Code :
  1. #include <stdio.h>
  2. void foo(char c) {
  3.     if (c == 'a') {
  4.         puts("a" );
  5.     } else {
  6.         puts("b" );
  7.     }
  8. }

j'ai:

00000000 <foo>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   80 7d 08 61             cmpb   $0x61,0x8(%ebp)
   7:   74 0f                   je     18 <foo+0x18>
   9:   c7 45 08 00 00 00 00    movl   $0x0,0x8(%ebp)
  10:   c9                      leave  
  11:   e9 fc ff ff ff          jmp    12 <foo+0x12>
  16:   89 f6                   mov    %esi,%esi
  18:   c7 45 08 02 00 00 00    movl   $0x2,0x8(%ebp)
  1f:   eb ef                   jmp    10 <foo+0x10>

Tu remarqueras

  • que le compilateur a utilise des constantes sur 8 bits (0x61)
  • que l'encodage des instructions est tres irregulier


 
CHAR_MAX+1 n'est garanti etre CHAR_MIN que si char n'est pas signe, donc que CHAR_MIN vaut 0.


 
Les fameuses constates dont tu me parles sont en plein dans un instruction, ce que le compilo essayera de faire des qu'il pourra, et dans ce cas, leur encodage se fait sur un nombre de bits dependant de l'encodage de l'instruction (et la faut sortir la doc du processeur). Il ne pourra le faire que dans certains cas particuilers.
 
Si tu met une valeur en dur en memoire, que le processeur ira chercher avec un ldr tu est presque obligé de l'aligner sur 32bits.
 
Quand a l'encodage des instructions, il est assez etrange, tu as mis les optimisation a bloc ?

Reply

Marsh Posté le 09-07-2007 à 19:43:11    

deadalnix a écrit :

Si tu met une valeur en dur en memoire, que le processeur ira chercher avec un ldr tu est presque obligé de l'aligner sur 32bits.[/quote]
 
Sur la plupart des processeurs -- il y a quelques exceptions, par exemple les premiers Alpha ou des processeurs adressables par mots plutôt que par byte -- il n'y aucune incitation à aligner des valeurs d'une longueur inférieure à 32 bits sur une frontière de 32 bits.
 
(Il n'y a aucune instruction ldr sur un x86).
 
[quote]Quand a l'encodage des instructions, il est assez etrange, tu as mis les optimisation a bloc ?


 
-O2 avec gcc si j'ai bonne mémoire.  Mais il me semble normal, qu'est-ce qui te semble étrange pour du x86?

Reply

Marsh Posté le 09-07-2007 à 21:58:59    

Bon bah je dois me tromper, j'aurais cru que les instructions seraient alignées sur les adresse qui vont bien.
 
Il y a quand meme un truc vicié dans ton exemple : ton 'a' n'est jamais utilisé que pour une comparaison avec un char (d'ou le fait qu'il doit en dur dans un instruction et du coup sur 8 bits). Si tu fais un sizeof('a') le valeur retournée devrait etre 4.

Reply

Marsh Posté le 09-07-2007 à 22:22:45    

Un Programmeur a écrit :

Vrai pour chaque opération individuellement, mais pas pour l'ensemble de l'expression.  Par exemple, dans 1.5 + 1 / 2
 
1/2 est calculé en entier, pas en flottant.


Tiens ? T'as raison. Je ne m'en étais jamais aperçu. Ptet parce que dans tous les calculs que je faisais, la priorité des opérateurs faisait que le calcul était bien exécuté. Pour reprendre ton exemple :
1.0 + 1 / 2 => Donnera 1.0 (il commence par faire 1/2 en entier et ajoute le résultat à 1.0)
1.0 / 2 + 1 => Donnera 1.5 (il commence par faire 1/2 en flottant et ajoute ce résultat à 1)
 

floboss07 a écrit :

En tout cas désolé mais j'avais pas eu le temps ces temps ci, et d'ailleur je viens de voir tout le bruit qu'a fait ma pauvre petite question (enfin surtout ta réponse en fait...! lol), quelle surprise! lol


Bienvenue dans le monde fantastique du C. A chaque réponse on se cherche la petite bête, on se contredit, on se chamaille, on s'insulte... c'est génial  :D - J'ai l'impression de me retrouver au milieu du village d'Astérix [:ddr555]


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 09-07-2007 à 22:32:21    

deadalnix a écrit :

Il y a quand meme un truc vicié dans ton exemple : ton 'a' n'est jamais utilisé que pour une comparaison avec un char (d'ou le fait qu'il doit en dur dans un instruction et du coup sur 8 bits). Si tu fais un sizeof('a') le valeur retournée devrait etre 4.


 
sizeof('a') == sizeof(int), nous sommes d'accord (C'est une différence entre le C et le C++, en C++ sizeof('a') == sizeof(char) == 1)

Reply

Marsh Posté le 09-07-2007 à 23:15:19    

Sve@r a écrit :

Bienvenue dans le monde fantastique du C. A chaque réponse on se cherche la petite bête, on se contredit, on se chamaille, on s'insulte... c'est génial  :D - J'ai l'impression de me retrouver au milieu du village d'Astérix [:ddr555]

Je comprends maintenant pourquoi tu te dis Gaulois :D

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed