À un même opérateur arithmétique (notion syntaxique) peuvent
correspondre plusieurs opérations (notion sémantique). Par exemple,
l'opération de division dépend du type des opérandes, selon
qu'ils sont entiers ou flottants : 5/2 a pour valeur tandis
que 5.0/2.0 a pour valeur
. On dit que l'opérateur
/ est surchargé.
Quand les opérandes d'une opération ne sont pas de même type (par exemple un int et un float), il y a conversion implicite de l'un d'eux dans le type de l'autre ; par exemple, int + float est converti en float + float. Cette conversion implicite se fait toujours dans la direction du << plus grand >> type : de int vers float, de float vers double.
Les conversions ascendantes entre types entiers d'une part, et entre types flottants d'autre part, se font toujours sans perte d'information :
Par contre, la conversion de int en float se fait avec une perte de précision, même si ces deux types ont généralement la même taille. Ces conversions implicites sont également appliquées lors du passage d'argument et lors du retour d'un appel de fonction. Par exemple, si une fonction f est déclarée int f(int), un appel f(2.1), avec un argument double conduira d'abord à une conversion de double en int : c'est donc f(2) qui sera invoquée.
Il existe aussi des conversions explicites, qui doivent figurer dans le
programme. Par exemple, pour effectuer une opération flottante quand
les opérandes sont entiers, il faut d'abord appliquer une conversion
explicite, ou coercition (en anglais, cast),
double() à l'un des opérandes : double(5)/2 et
5/double(2) ont ainsi pour valeur et double(5) a
pour valeur le flottant
. Il existe des coercitions entre tous les
types numériques. Les conversions descendantes, par exemple de
int vers char, peuvent conduire à une perte
d'information, par troncature. Les conversions entre float et
int, même si ces deux types ont généralement la même taille se
font toujours avec perte d'information. Seule la conversion
d'int en double se fait généralement sans perte
d'information.