Les instructions élémentaires de C#

 On distingue
1 les instructions élémentaires exécutées par l'ordinateur.
2 les instructions de contrôle du déroulement du programme.
Les instructions élémentaires apparaissent clairement lorsqu'on considère la structure d'un micro-ordinateur et de ses périphériques.
                            U. C      MEMOIRE          ECRAN 
                          +-------------------+      +-------+
                          ¦   2  <-+-->       ¦  3   ¦       ¦
  +-----------+    1      ¦        ¦      ----+------+->     ¦
  ¦ CLAVIER   +-----------+--------+-->       ¦      ¦       ¦
  +-----------+           +-------------------+      +-------+
1. lecture d'informations provenant du clavier
2. traitement d'informations
3. écriture d'informations à l'écran

1.3.1 Ecriture sur écran
Il existe différentes instructions d'écriture à l'écran :
Console.Out.WriteLine(expression)
Console.WriteLine(expression)
Console.Error.WriteLine (expression)
où expression est tout type de donnée qui puisse être converti en chaîne de caractères pour être affiché à l'écran. Tous les objets de
C# ou .NET ont une méthode ToString() qui est utilisée pour faire cette conversion.
La classe System.Console donne accès  aux opérations d'écriture écran (Write, WriteLine). La classe Console a deux propriétés Out et
Error qui sont des flux d'écriture de type TextWriter :
• Console.WriteLine() est équivalent à Console.Out.WriteLine() et écrit sur le flux Out associé habituellement à l'écran.
• Console.Error.WriteLine() écrit sur le flux Error, habituellement associé lui aussi à l'écran.

Les flux Out et Error peuvent être redirigés vers des fichiers texte au moment de l'exécution du programme comme nous le verrons
prochainement.
1.3.2 Lecture de données tapées au clavier
Le flux de données provenant du clavier est désigné par l'objet Console.In de type TextReader. Ce type d'objets permet de lire une
ligne de texte avec la méthode ReadLine :
string ligne=Console.In.ReadLine();
La classe Console offre une méthode ReadLine associée par défaut au flux In. On peut donc écrire écrire :
string ligne=Console.ReadLine();
La ligne tapée au clavier est rangée dans la variable ligne et peut ensuite être exploitée par le programme. Le flux In peut être redirigé
vers un fichier, comme les flux Out et Error.
1.3.3 Exemple d'entrées-sorties
Voici un court programme d'illustration des opérations d'entrées-sorties clavier/écran :

1. using System;
2.
3. namespace Chap1 {
4. // classe de test
5. public class P03 {
6. public static void Main() {
7.
8. // écriture sur le flux Out
9. object obj = new object();
10. Console.Out.WriteLine(obj);
11.
12. // écriture sur le flux Error
13. int i = 10;
14. Console.Error.WriteLine("i=" + i);
15.
16. // lecture d'une ligne saisie au clavier
17. Console.Write("Tapez une ligne : ");
18. string ligne = Console.ReadLine();
19. Console.WriteLine("ligne={0}", ligne);
20. }//fin main
21. }//fin classe
22.}
• ligne 9 : obj est une référence d'objet
• ligne 10 : obj est écrit à l'écran. Par défaut, c'est la méthode obj.ToString() qui est appelée.
• ligne 14 : on peut aussi écrire :
Console.Error.WriteLine("i={0}",i);
Le 1er paramètre "i={0}" est le format d'affichage, les autres paramètres, les expressions à afficher. Les éléments {n} sont
des paramètres "positionnels". A l'exécution, le paramètre {n} est remplacé par la valeur de l'expression n° n.
Le résultat de l'exécution est le suivant :
1. System.Object
2. i=10
3. Tapez une ligne : je suis là
4. ligne=je suis là
• ligne 1 : l'affichage produit par la ligne 10 du code. La méthode obj.ToString() a affiché le nom du type de la variable obj :
System.Object. Le type object est un alias C# du type .NET System.Object.

1.3.4 Redirection des E/S
Il existe sous DOS et UNIX trois périphériques standard appelés :
1. périphérique d'entrée standard - désigne par défaut le clavier et porte le n° 0

2. périphérique de sortie standard - désigne par défaut l'écran et porte le n° 1
3. périphérique d'erreur standard - désigne par défaut l'écran et porte le n° 2
En C#, le flux d'écriture Console.Out écrit sur le périphérique 1, le flux d'écriture Console.Error écrit sur le périphérique 2 et le flux de
lecture Console.In lit les données provenant du périphérique 0.
Lorsqu'on lance un programme sous Dos ou Unix, on peut fixer quels seront les périphériques 0, 1 et 2 pour le programme
exécuté. Considérons la ligne de commande suivante :
pg arg1 arg2 .. argn
Derrière les arguments argi du programme pg, on peut rediriger les périphériques d'E/S standard vers des fichiers:
0<in.txt
le flux d'entrée standard n° 0 est redirigé vers le fichier  in.txt. Dans le programme le flux  Console.In
prendra donc ses données dans le fichier in.txt.
1>out.txt
redirige la sortie n° 1 vers le fichier out.txt. Cela entraîne que dans le programme le flux Console.Out écrira
ses données dans le fichier out.txt
1>>out.txt
idem, mais les données écrites sont ajoutées au contenu actuel du fichier out.txt.
2>error.txt
redirige la sortie n° 2 vers le fichier error.txt. Cela entraîne que dans le programme le flux Console.Error
écrira ses données dans le fichier error.txt
2>>error.txt
idem, mais les données écrites sont ajoutées au contenu actuel du fichier error.txt.
1>out.txt
2>error.txt
Les périphériques 1 et 2 sont tous les deux redirigés vers des fichiers
On notera que pour rediriger les flux d'E/S du programme pg vers des fichiers, le programme pg n'a pas besoin d'être modifié. C'est
le système d'exploitation qui fixe la nature des périphériques 0,1 et 2. Considérons le programme suivant :

1. using System;
2.
3. namespace Chap1 {
4.
5. // redirections
6. public class P04 {
7. public static void Main(string[] args) {
8. // lecture flux In
9. string data = Console.In.ReadLine();
10. // écriture flux Out
11. Console.Out.WriteLine("écriture dans flux Out : " + data);
12. // écriture flux Error
13. Console.Error.WriteLine("écriture dans flux Error : " + data);
14. }//Main
15. }//classe
16.}
Générons l'exécutable de ce code source :

Les instructions élémentaires de C#
Les instructions élémentaires de C#

 • en [1] : l'exécutable est créé par clic droit sur le projet / Build
• en [2] : dans une fenêtre Dos, l'exécutable 04.exe a été créé dans le dossier bin/Release du projet.
Emettons les commandes suivantes dans la fenêtre Dos [2] :
1. ...\04\bin\Release>echo test >in.txt
2. ...\04\bin\Release>more in.txt
3. test
4. ...\04\bin\Release>04 0<in.txt 1>out.txt 2>err.txt
5. ...\04\bin\Release>more out.txt
6. écriture dans flux Out : test
7. ...\04\bin\Release>more err.txt
8. écriture dans flux Error : test
• ligne 1 : on met la chaîne test dans le fichier in.txt
• lignes 2-3 : on affiche le contenu du fichier in.txt pour vérification
• ligne 4 : exécution du programme 04.exe. Le flux In est redirigé vers le fichier in.txt, le flux Out vers le fichier out.txt, le flux
Error vers le fichier err.txt.  L'exécution ne provoque aucun affichage.
• lignes 5-6 : contenu du fichier out.txt. Ce contenu nous montre que :
• le fichier in.txt a été lu
• l'affichage écran a été redirigé vers out.txt
• lignes 7-8 : vérification analogue pour le fichier err.txt
On voit clairement que les flux Out et In n'écrivent pas sur les mêmes périphériques puisqu'on a pu les rediriger séparément.
1.3.5 Affectation de la valeur d'une expression à une variable
On s'intéresse ici à l'opération  variable=expression;
L'expression peut être de type :  arithmétique, relationnelle, booléenne, caractères
1.3.5.1 Interprétation de l'opération d'affectation
L'opération  variable=expression;
est elle-même une expression dont l'évaluation se déroule de la façon suivante :
• la partie droite de l'affectation est évaluée : le résultat est une valeur V.
• la valeur V est affectée à la variable
• la valeur V est aussi la valeur de l'affectation vue cette fois en tant qu'expression.

C'est ainsi que l'opération
V1=V2=expression
est légale. A cause de la priorité, c'est l'opérateur = le plus à droite qui va être évalué.  On a donc
V1=(V2=expression)
L'expression V2=expression est évaluée et a pour valeur V. L'évaluation de cette expression a provoqué l'affectation de V à V2.
L'opérateur = suivant est alors évalué sous la forme :
V1=V
La valeur de cette expression est encore V. Son évaluation provoque l'affectation de V à V1.
Ainsi donc, l'opération V1=V2=expression
est une expression dont l'évaluation
1 provoque l'affectation de la valeur de expression aux variables V1 et V2
2 rend comme résultat la valeur de expression.
On peut généraliser à une expression du type :
V1=V2=....=Vn=expression
1.3.5.2 Expression arithmétique
Les opérateurs des expressions arithmétiques sont les suivants :
+ addition
- soustraction
* multiplication
/ division : le résultat est le quotient exact si l'un au moins des opérandes est réel. Si les deux opérandes sont entiers le
résultat est le quotient entier. Ainsi 5/2 -> 2 et 5.0/2 ->2.5.
% division : le résultat est le reste quelque soit la nature des opérandes, le quotient étant lui entier. C'est donc l'opération
modulo.
Il existe diverses fonctions mathématiques. En voici quelques-unes :
double Sqrt(double x)
racine carrée
double Cos(double x)
Cosinus
double Sin(double x)
Sinus
double Tan(double x)
Tangente
double Pow(double x,double y)
x à la puissance y (x>0)
double Exp(double x)
Exponentielle
double Log(double x)
Logarithme népérien
double Abs(double x)
valeur absolue
etc...
Toutes ces fonctions sont définies dans une classe C# appelée Math. Lorsqu'on les utilise, il faut les préfixer avec le nom de la
classe où elles sont définies. Ainsi on écrira :
double x, y=4;
x=Math.Sqrt(y);
La définition complète de la classe Math est la suivante :

1.3.5.3 Priorités dans l'évaluation des expressions arithmétiques
La priorité des opérateurs lors de l'évaluation d'une expression arithmétique est la suivante (du plus prioritaire au moins prioritaire) :
[fonctions], [ ( )],[ *, /, %], [+, -]
Les opérateurs d'un même bloc [ ] ont même priorité.
1.3.5.4 Expressions relationnelles
Les opérateurs sont les suivants :
       <, <=, ==, !=, >, >=
priorités des opérateurs
1. >, >=, <, <=
2. ==, !=
Le résultat d'une expression relationnelle est le booléen false  si expression est fausse, true sinon.
      bool fin;
      int x=...;
      fin=x>4;
Comparaison de deux caractères
Soient deux caractères C1 et C2. Il est possible de les comparer avec les opérateurs
<, <=, ==, !=, >, >=
Ce sont alors leurs codes Unicode, qui sont des nombres, qui sont alors comparés. Selon l'ordre Unicode on a les relations
suivantes :

espace < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. <'z'
Comparaison de deux chaînes de caractères
Elles sont comparées caractère par caractère. La première inégalité rencontrée entre deux caractères induit une inégalité de même
sens sur les chaînes.
Exemples :
Soit à comparer les chaînes "Chat" et "Chien"

"Chat" "Chien"
-----------------------
'C' = 'C'
'h' = 'h'
'a' < 'i'
Cette dernière inégalité permet de dire que "Chat" < "Chien".
Soit à comparer les chaînes "Chat" et "Chaton". Il y a égalité tout le temps jusqu'à épuisement de la chaîne "Chat". Dans ce cas, la
chaîne épuisée est déclarée la plus "petite". On a donc la relation
"Chat" < "Chaton".
Fonctions de comparaison de deux chaînes
On peut utiliser les opérateurs relationnels == et != pour tester l'égalité  ou non de deux chaînes, ou bien la méthode Equals de la
classe System.String. Pour les relations < <= > >=, il faut utiliser la méthode CompareTo de la classe System.String :
1. using System;
2.
3. namespace Chap1 {
4. class P05 {
5. static void Main(string[] args) {
6. string chaine1="chat", chaine2="chien";
7. int n = chaine1.CompareTo(chaine2);
8. bool egal = chaine1.Equals(chaine2);
9. Console.WriteLine("i={0}, egal={1}", n, egal);
10. Console.WriteLine("chien==chaine1:{0},chien!=chaine2:{1}", "chien"==chaine1,"chien" !=
chaine2);
11. }
12. }
13.}
Ligne 7, la variable i aura la valeur :
0 si les deux chaînes sont égales
1 si chaîne n°1 > chaîne n°2
-1 si chaîne n°1 < chaîne n°2

Ligne 8, la variable egal aura la valeur true si les deux chaînes sont égales, false sinon. Ligne 10, on utilise les opérateurs == et != pour
vérifier l'égalité ou non de deux chaînes.
Les résultats de l'exécution :
1. i=-1, egal=False
2. chien==chaine1:False,chien!=chaine2:False
1.3.5.5 Expressions booléennes
Les opérateurs utilisables sont AND (&&)  OR(||) NOT (!). Le résultat d'une expression booléenne est un booléen.
priorités des opérateurs  :
1. !
2. &&
3. ||
double x = 3.5;
bool valide = x > 2 && x < 4;
Les opérateurs relationnels ont priorité sur les opérateurs && et ||.
1.3.5.6 Traitement de bits
Les opérateurs
Soient  i et j deux entiers.
i<<n
décale i de n bits sur la gauche. Les bits entrants sont des zéros.
i>>n
décale i de n bits sur la droite. Si i est un entier signé (signed char, int, long) le bit de signe est préservé.
i & j
fait le ET logique de i et j bit à bit.
i | j
fait le OU logique de i et j bit à bit.
~i
complémente i à 1
i^j
fait le OU EXCLUSIF de i et j
Soit le code suivant :
1. short i = 100, j = -13;
2. ushort k = 0xF123;
3. Console.WriteLine("i=0x{0:x4}, j=0x{1:x4}, k=0x{2:x4}", i,j,k);
4. Console.WriteLine("i<<4=0x{0:x4}, i>>4=0x{1:x4},k>>4=0x{2:x4},i&j=0x{3:x4},i|
j=0x{4:x4},~i=0x{5:x4},j<<2=0x{6:x4},j>>2=0x{7:x4}", i << 4, i >> 4, k >> 4, (short)(i & j),
(short)(i | j), (short)(~i), (short)(j << 2), (short)(j >> 2));
• le format {0:x4} affiche le paramètre n° 0 au format hexadécimal (x) avec 4 caractères (4).
Les résultats de l'exécution sont les suivants :
1. i=0x0064, j=0xfff3, k=0xf123
2. i<<4=0x0640, i>>4=0x0006,k>>4=0x0f12,i&j=0x0060,i|j=0xfff7,~i=0xff9b,j<<2=0xffcc,j>>2=0xfffc
1.3.5.7 Combinaison d'opérateurs
       a=a+b peut s'écrire a+=b
       a=a-b peut s'écrire a-=b
Il en est de même avec les opérateurs /, %,* ,<<, >>, &, |, ^. Ainsi  a=a/2; peut s'écrire a/=2;
1.3.5.8 Opérateurs d'incrémentation et de décrémentation
La notation variable++ signifie variable=variable+1 ou encore variable+=1
La notation variable-- signifie variable=variable-1 ou encore variable-=1.
1.3.5.9 L'opérateur ternaire ?
L'expression
expr_cond ? expr1:expr2
est évaluée de la façon suivante :
1 l'expression expr_cond est évaluée. C'est une expression conditionnelle à valeur vrai ou faux
2 Si elle est vraie, la valeur de l'expression est celle de expr1 et expr2 n'est pas évaluée.
3 Si elle est fausse, c'est l'inverse qui se produit : la valeur de l'expression est celle de expr2 et expr1 n'est pas évaluée.
L'opération i=(j>4 ? j+1:j-1); affectera à la variable i : j+1 si j>4, j-1 sinon. C'est la même chose que d'écrire if(j>4) i=j+1; else i=j-1;
mais c'est plus concis.
1.3.5.10 Priorité générale des opérateurs
() []  fonction                   gd
! ~ ++ --                         dg
new (type) opérateurs cast        dg
*  /  %                           gd
+  -                              gd
<<  >>                            gd
< <=  > >= instanceof             gd
==    !=                          gd
&                                 gd
^                                 gd

|                                 gd
&&                                gd
||                                gd
?   :                             dg
= += -= etc. .                    dg
gd indique qu'a priorité égale, c'est la priorité gauche-droite qui est observée. Cela signifie que lorsque dans une expression, l'on a
des opérateurs de même priorité, c'est l'opérateur le plus à gauche dans l'expression qui est évalué en premier. dg indique une
priorité droite-gauche.
1.3.5.11 Les changements de type
Il est possible, dans une expression, de changer momentanément le codage d'une valeur. On appelle cela changer le type d'une
donnée ou en anglais type casting. La syntaxe du changement du type d'une valeur dans une expression est  la suivante:
    (type) valeur
La valeur prend alors le type indiqué. Cela entraîne un changement de codage de la valeur.
1. using System;
2.
3. namespace Chap1 {
4. class P06 {
5. static void Main(string[] args) {
6. int i = 3, j = 4;
7. float f1=i/j;
8. float f2=(float)i/j;
9. Console.WriteLine("f1={0}, f2={1}",f1,f2);
10. }
11. }
12.}

• ligne 7, f1 aura la valeur 0.0. La division 3/4 est une division entière puisque les deux opérandes sont de type int.
• ligne 8, (float)i est la valeur de i transformée en float. Maintenant, on a une division entre un réel de type float et un entier de
type int. C'est la division entre nombres réels qui est alors faite. La valeur de j sera elle également transformée en type float,
puis la division des deux réels sera faite. f2 aura alors la valeur 0,75.
Voici les résultats de l'exécution :
f1=0, f2=0,75
Dans l'opération (float)i :
• i est une valeur codée de façon exacte sur 2 octets
• (float) i est la même valeur codée de façon approchée en réel sur 4 octets
Il y a donc transcodage de la valeur de i. Ce transcodage n'a lieu que le temps d'un calcul, la variable i conservant toujours son type
int.

Published By Drupal french Study