C Variables et types

Une introduction à la gestion des variables en C et des types de base

C est un langage typé statiquement.

Cela signifie que toute variable a un type associé, et ce type est connu au moment de la compilation.

C'est très différent de la façon dont vous travaillez avec des variables en Python, JavaScript, PHP et d'autres langages interprétés.

Lorsque vous créez une variable en C, vous devez spécifier le type d'une variable lors de la déclaration.

Dans cet exemple, nous initialisons une variableageavec typeint:

int age;

Un nom de variable peut contenir n'importe quelle lettre majuscule ou minuscule, peut contenir des chiffres et le caractère de soulignement, mais il ne peut pas commencer par un chiffre.AGEetAge10sont des noms de variables valides,1agen'est pas.

Vous pouvez également initialiser une variable lors de la déclaration, en spécifiant la valeur initiale:

int age = 37;

Une fois que vous déclarez une variable, vous êtes alors en mesure de l'utiliser dans votre code de programme, et vous pouvez modifier sa valeur à tout moment, en utilisant le=opérateur par exemple, comme dansage = 100;, à condition que la nouvelle valeur soit du même type.

Dans ce cas:

#include <stdio.h>

int main(void) {
	int age = 0;
	age = 37.2;
	printf("%u", age);
}

le compilateur lèvera un avertissement au moment de la compilation et convertira le nombre décimal en une valeur entière.

LeCles types de données intégrés sontint,char,short,long,float,double,long double. Découvrons-en plus à ce sujet.

Nombres entiers

C nous fournit les types suivants pour définir des valeurs entières:

  • char
  • int
  • short
  • long

La plupart du temps, vous utiliserez probablement unintpour stocker un entier. Mais dans certains cas, vous voudrez peut-être choisir l'une des 3 autres options.

Lechartype est couramment utilisé pour stocker les lettres du graphique ASCII, mais il peut être utilisé pour contenir de petits entiers de-128à127. Cela prend au moins 1 octet.

intprend au moins 2 octets.shortprend au moins 2 octets.longprend au moins 4 octets.

Comme vous pouvez le voir, les mêmes valeurs ne nous sont pas garanties pour différents environnements. Nous n'avons qu'une indication. Le problème est que les nombres exacts qui peuvent être stockés dans chaque type de données dépendent de l'implémentation et de l'architecture.

Nous sommes garantis queshortn'est pas plus long queint. Et nous sommes garantislongn'est pas plus court queint.

La norme ANSI C spec détermine les valeurs minimales de chaque type, et grâce à elle, nous pouvons au moins savoir quelle est la valeur minimale que nous pouvons espérer avoir à notre disposition.

Si vous programmez C sur un Arduino, une carte différente aura des limites différentes.

Sur une carte Arduino Uno,intstocke une valeur de 2 octets, allant de-32,768à32,767. On a Arduino MKR 1010, intstocke une valeur de 4 octets, allant de-2,147,483,648à2,147,483,647. Une grande différence.

Sur toutes les cartes Arduino,shortstocke une valeur de 2 octets, allant de-32,768à32,767.longstocker 4 octets, allant de-2,147,483,648à2,147,483,647.

Entiers non signés

Pour tous les types de données ci-dessus, nous pouvons ajouterunsignedpour commencer la plage à 0, au lieu d'un nombre négatif. Cela peut avoir du sens dans de nombreux cas.

  • unsigned charvariera de0au moins255
  • unsigned intvariera de0au moins65,535
  • unsigned shortvariera de0au moins65,535
  • unsigned longvariera de0au moins4,294,967,295

Le problème du débordement

Compte tenu de toutes ces limites, une question pourrait se poser: comment pouvons-nous nous assurer que nos chiffres ne dépassent pas la limite? Et que se passe-t-il si nous dépassons la limite?

Si vous avez ununsigned intnombre à 255, et vous l'incrémentez, vous obtiendrez 256 en retour. Comme prévu. Si tu as ununsigned charnombre à 255, et vous l'incrémentez, vous obtiendrez 0 en retour. Il se réinitialise à partir de la valeur initiale possible.

Si tu as ununsigned charnuméro à 255 et vous y ajoutez 10, vous obtiendrez le numéro9:

#include <stdio.h>

int main(void) {
  unsigned char j = 255;
  j = j + 10;
  printf("%u", j); /* 9 */
}

Si vous avez une valeur signée, le comportement n'est pas défini. Cela vous donnera essentiellement un nombre énorme qui peut varier, comme dans ce cas:

#include <stdio.h>

int main(void) {
  char j = 127;
  j = j + 10;
  printf("%u", j); /* 4294967177 */
}

En d'autres termes, C ne vous protège pas du dépassement des limites d'un type. Vous devez vous en occuper vous-même.

Avertissements lors de la déclaration du mauvais type

Lorsque vous déclarez la variable et l'initialisez avec une valeur incorrecte, legccle compilateur (celui que vous utilisez probablement) devrait vous avertir:

#include <stdio.h>

int main(void) {
  char j = 1000;
}
hello.c:4:11: warning: implicit conversion from 'int' to
      'char' changes value from 1000 to -24
      [-Wconstant-conversion]
        char j = 1000;
             ~   ^~~~
1 warning generated.

And it also warns you in direct assignments:

#include <stdio.h>

int main(void) {
  char j;
  j = 1000;
}

But not if you increase the number using for example +=:

#include <stdio.h>

int main(void) {
  char j = 0;
  j += 1000;
}

Floating point numbers

Floating point types can represent a much larger set of values than integers can, and can also represent fractions, something that integers can’t do.

Using floating point numbers, we represent numbers as decimal numbers times powers of 10.

You might see floating point numbers written as

  • 1.29e-3
  • -2.3e+5

and in other seemingly weird ways.

The following types:

  • float
  • double
  • long double

are used to represent numbers with decimal points (floating point types). All can represent both positive and negative numbers.

The minimum requirements for any C implementation is that float can represent a range between 10^-37 and 10^+37, and is typically implemented using 32 bits. double can represent a bigger set of numbers. long double can hold even more numbers.

The exact figures, as with integer values, depend on the implementation.

On a modern Mac, a float is represented in 32 bits, and has a precision of 24 significant bits, 8 bits are used to encode the exponent. A double number is represented in 64 bits, with a precision of 53 significant bits, 11 bits are used to encode the exponent. The type long double is represented in 80 bits, has a precision of 64 significant bits, 15 bits are used to encode the exponent.

On your specific computer, how can you determine the specific size of the types? You can write a program to do that:

#include <stdio.h>

int main(void) {
  printf("char size: %lu bytes\n", sizeof(char));
  printf("int size: %lu bytes\n", sizeof(int));
  printf("short size: %lu bytes\n", sizeof(short));
  printf("long size: %lu bytes\n", sizeof(long));
  printf("float size: %lu bytes\n", sizeof(float));
  printf("double size: %lu bytes\n", sizeof(double));
  printf("long double size: %lu bytes\n", sizeof(long double));
}

In my system, a modern Mac, it prints:

char size: 1 bytes
int size: 4 bytes
short size: 2 bytes
long size: 8 bytes
float size: 4 bytes
double size: 8 bytes
long double size: 16 bytes  

Download my free C Handbook


More clang tutorials: