Les opérateurs arithmétiques appliquent des opérations mathématiques standard à leurs opérandes.

Opérateur Nom de l'opérateur Exemple Résultat
+ unaire plus +a la valeur de a après les promotions
- unaire moins -a le négatif de a
+ addition a + b l'addition de a et b
- soustraction a - b la soustraction de b de a
* produit a * b le produit de a et b
/ division a / b la division de a par b
% modulo a % b le reste de a divisé par b
~ NON par bit ~a le NOT bit à bit de a
& ET au sens du bit a & b le ET binaire de a et b
| OU par bit a | b le OU bit à bit de a et b
^ XOR au sens du bit a ^ b le XOR au niveau des bits de a et b
<< décalage à gauche par bit a << b a décalé à gauche par b
>> décalage à droite par bit a >> b a décalé à droite par b

Débordements

L'arithmétique des entiers non signés est toujours effectuée modulo 2.n
où n est le nombre de bits de ce nombre entier particulier. Par exemple, pour unsigned inton ajoute un à UINT_MAX donne ​0​et en soustrayant un à ​0​ donne UINT_MAX.

Lorsque l'opération arithmétique sur les entiers signés déborde (le résultat ne rentre pas dans le type de résultat), le comportement est indéfini : il peut s'enrouler selon les règles de la représentation (typiquement le complément à 2), il peut se piéger sur certaines plateformes ou en raison des options du compilateur (par ex. -ftrapv dans GCC et Clang), ou peut être complètement optimisé par le compilateur.

Environnement à virgule flottante

Si

est réglé sur ON, tous les opérateurs arithmétiques en virgule flottante obéissent à la direction d'arrondi en virgule flottante actuelle et signalent les erreurs arithmétiques en virgule flottante comme spécifié dans la section math_errhandling sauf s'ils font partie d'un initialisateur statique (auquel cas les exceptions en virgule flottante ne sont pas levées et le mode d'arrondi est au plus proche).

Contraction en virgule flottante

Sauf si #pragma STDC FP_CONTRACT ne soit réglé sur OFF, toute l'arithmétique en virgule flottante peut être effectuée comme si les résultats intermédiaires avaient une plage et une précision infinies, c'est-à-dire des optimisations qui omettent les erreurs d'arrondi et les exceptions en virgule flottante qui seraient observées si l'expression était évaluée exactement comme elle est écrite. Par exemple, permet l'implémentation de (x*y) + z avec une seule instruction de multiplicateur-additionneur fusionné du CPU ou l'optimisation de a = x*x*x*x; comme tmp = x*x; a = tmp*tmp.

Sans rapport avec la contractualisation, les résultats intermédiaires de l'arithmétique à virgule flottante peuvent avoir une plage et une précision différentes de celles indiquées par son type, cf. FLT_EVAL_METHOD.

Arithmétique unaire

Les expressions des opérateurs arithmétiques unaires ont la forme.

+expression (1)
-expression (2)

1) unaire plus (promotion)2) unaire moins (négation)

où.

expression - expression de tout type arithmétique

Le plus unaire et le moins unaire appliquent d'abord des promotions intégrales à leur opérande, puis.

  • le plus unaire retourne la valeur après la promotion
  • unary minus renvoie le négatif de la valeur après promotion (sauf que le négatif d'un NaN est un autre NaN).

Le type de l'expression est le type après promotion, et la catégorie de valeur est non-lvalue.

Notes

Le moins unaire invoque un comportement non défini dû à un débordement d'entier signé lorsqu'il est appliqué à... INT_MIN, LONG_MINou LLONG_MIN, sur les plateformes typiques (complément à 2).

En C++, l'opérateur unaire + peut également être utilisé avec d'autres types intégrés tels que les tableaux et les fonctions, ce qui n'est pas le cas en C.

#include#includeintmain(void){char c ='a';printf("sizeof char: %zu sizeof int: %zun",sizeof c,sizeof+c);printf("-1, where 1 is signed: %dn",-1);printf("-1, where 1 is unsigned: %un",-1u);double complex z =1+2*I;printf("-(1+2i) = %.1f%+.1fn",creal(-z),cimag(-z));}

Sortie possible :

sizeofchar:1sizeofint:4-1, where 1 is signed:-1-1, where 1 is unsigned:4294967295-(1+2i)=-1.0-2.0

Opérateurs additifs

Les expressions des opérateurs arithmétiques additifs binaires ont la forme.

lhs+rhs (1)
lhs-rhs (2)

1) addition : lhs et rhs doit être l'un des éléments suivants

  • les deux ont des types arithmétiques, y compris complexes et imaginaires
  • l'un est un pointeur vers un type d'objet complet, l'autre a un type entier

2) soustraction : lhs et rhs doit être l'un des éléments suivants

  • les deux ont des types arithmétiques, y compris complexes et imaginaires
  • lhs a un pointeur vers un type d'objet complet, rhs a un type entier
  • les deux sont des pointeurs vers des objets complets de types compatibles, en ignorant les qualificatifs.

Addition et soustraction arithmétiques

Si les deux opérandes ont des types arithmétiques, alors.

  • d'abord, les conversions arithmétiques habituelles sont effectuées.
  • ensuite, les valeurs des opérandes après conversions sont additionnées ou soustraites selon les règles habituelles des mathématiques (pour la soustraction, rhs est soustrait de lhs), sauf que
    • si un des opérandes est NaN, le résultat est NaN.
    • l'infini moins l'infini est NaN et FE_INVALID est élevé
    • l'infini plus l'infini négatif est NaN et FE_INVALID est élevé

L'addition et la soustraction complexes et imaginaires sont définies comme suit (notez que le type de résultat est imaginaire si les deux opérandes sont imaginaires et complexe si un opérande est réel et l'autre imaginaire, comme spécifié par les conversions arithmétiques habituelles) :

+ ou - u iv u + iv
x x ± u x ± iv (x ± u) ± iv
iy ±u + iy i(y ± v) ±u + i(y ± v)
x + iy (x ± u) + iy x + i(y ± v) (x ± u) + i(y ± v)
// work in progress// note: take part of the c/language/conversion example

Arithmétique des pointeurs

  • Si le pointeur P pointe sur un élément d'un tableau dont l'indice Ialors
    • P+N et N+P sont des pointeurs qui pointent sur un élément du même tableau avec l'index I+N
    • P-N est un pointeur qui pointe sur un élément du même tableau avec l'index {tt|I-N}}.

Ce comportement n'est défini que si le pointeur d'origine et le pointeur de résultat pointent tous deux sur des éléments du même tableau ou sur un élément situé au-delà de la fin de ce tableau. Notez que l'exécution de p-1 lorsque p pointe sur le premier élément d'un tableau est un comportement non défini et peut échouer sur certaines plateformes.

  • Si le pointeur P1 pointe sur un élément d'un tableau dont l'indice I (ou un après la fin) et P2 pointe sur un élément du même tableau avec l'indice J (ou un élément après la fin), alors
    • P1-P2 a une valeur égale à J-I et le type ptrdiff_t (qui est un type d'entier signé, généralement deux fois moins grand que la taille du plus grand objet qui peut être déclaré).

Le comportement est défini uniquement si le résultat s'inscrit dans le type ptrdiff_t.

Pour les besoins de l'arithmétique des pointeurs, un pointeur vers un objet qui n'est un élément d'aucun tableau est traité comme un pointeur vers le premier élément d'un tableau de taille 1.

// work in progressint n =4, m =3;int a[n][m];// VLA of 4 VLAs of 3 ints eachint(*p)[m]= a;// p == &a[0] 
p = p +1;// p == &a[1] (pointer arithmetic works with VLAs just the same)(*p)[2]=99;// changes a[1][2]

Opérateurs multiplicatifs

Les expressions des opérateurs arithmétiques multiplicatifs binaires ont la forme.

lhs*rhs (1)
lhs/rhs (2)
lhs%rhs (3)

1) multiplication. lhs et rhs doivent avoir des types arithmétiques 2) division. lhs et rhs doivent avoir des types arithmétiques 3) reste. lhs et rhs doivent avoir des types entiers

  • d'abord, les conversions arithmétiques habituelles sont effectuées. Ensuite...

Multiplication

L'opérateur binaire * effectue la multiplication de ses opérandes (après les conversions arithmétiques habituelles) en suivant les définitions arithmétiques habituelles, à l'exception de ce qui suit .

  • si un opérande est un NaN, le résultat est un NaN.
  • la multiplication de l'infini par zéro donne NaN et FE_INVALID est soulevée
  • multiplication de l'infini par un non nul donne l'infini (même pour les arguments complexes).

Parce qu'en C, toute valeur complexe ayant au moins une partie infinie comme un infini même si son autre partie est un NaN, les règles arithmétiques habituelles ne s'appliquent pas à la multiplication complexe-complexe. D'autres combinaisons d'opérandes flottants suivent le tableau suivant :

* u iv u + iv
x xu i(xv) (xu) + i(xv)
iy i(yu) -yv (-yv) + i(yu)
x + iy (xu) + i(yu) (-yv) + i(xv) règles spéciales

Outre la gestion de l'infini, la multiplication complexe n'est pas autorisée à faire déborder les résultats intermédiaires, sauf lorsque #pragma STDC CX_LIMITED_RANGE est réglé sur ON, auquel cas la valeur peut être calculée comme si par (x+iy)×(u+iv) = (xu-yv)+i(yu+xv), le programmeur assumant la responsabilité de limiter la plage des opérandes et de traiter les infinis.

Malgré l'interdiction du débordement indu, la multiplication complexe peut soulever des exceptions fallacieuses en virgule flottante (sinon, il est prohibitivement difficile d'implémenter des versions sans débordement).

#include#include#include#includeintmain(void){// TODO simpler cases, take some from C++double complex z =(1+0*I)*(INFINITY + I*INFINITY);// textbook formula would give// (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN// but C gives a complex infinityprintf("%f + i*%fn",creal(z),cimag(z));// textbook formula would give// cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN// but C gives  ±∞+i*nandouble complex y =cexp(INFINITY + I*NAN);printf("%f + i*%fn",creal(y),cimag(y));}

Sortie possible :

inf + i*inf 
inf + i*nan

Division

L'opérateur binaire / divise le premier opérande par le second (après les conversions arithmétiques habituelles) en suivant les définitions arithmétiques habituelles, sauf que.

  • lorsque le type après conversions arithmétiques usuelles est un type entier, le résultat est le quotient algébrique (et non une fraction), arrondi dans une direction définie par l'implémentation.(jusqu'à C99)tronqué vers zéro(depuis C99)
  • si un opérande est un NaN, le résultat est un NaN
  • si le premier opérande est une infinité complexe et que le second opérande est fini, alors le

Le résultat de l'opérateur / est un infini complexe.

  • si le premier opérande est fini et que le second opérande est une infinité complexe, alors l'opérateur

résultat de l'opérateur / est un zéro.

Parce qu'en C, toute valeur complexe avec au moins une partie infinie comme une infinité même si son autre partie est un NaN, les règles arithmétiques habituelles ne s'appliquent pas à la division complexe-complexe. D'autres combinaisons d'opérandes flottants suivent le tableau suivant :

/ u iv
x x/u i(-x/v)
iy i(y/u) y/v
x + iy (x/u) + i(y/u) (y/v) + i(-x/v)

Outre la gestion de l'infini, la division complexe n'est pas autorisée à faire déborder les résultats intermédiaires, sauf lorsque #pragma STDC CX_LIMITED_RANGE est réglé sur ON, auquel cas la valeur peut être calculée comme si par (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u 2
+v 2
), car le programmeur assume la responsabilité de limiter la plage des opérandes et de traiter les infinis.

Malgré l'interdiction du débordement indu, la division complexe peut soulever des exceptions fallacieuses en virgule flottante (sinon, il est excessivement difficile d'implémenter des versions sans débordement).

Si le second opérande est zéro, le comportement est indéfini, sauf que si l'arithmétique à virgule flottante IEEE est supportée, et que la division en virgule flottante a lieu, alors .

  • La division d'un nombre non nul par ±0,0 donne l'infini correctement signé et... FE_DIVBYZERO est relevé
  • La division de 0,0 par 0,0 donne NaN et FE_INVALID est soulevé

Reste

L'opérateur binaire % donne le reste de la division du premier opérande par le second (après les conversions arithmétiques habituelles).

Le signe du reste est défini de telle sorte que si le quotient a/b est représentable dans le type de résultat, alors (a/b)*b + a%b == a.

Si le second opérande est nul, le comportement est indéfini.

Si le quotient a/b n'est pas représentable dans le type de résultat, le comportement des deux opérations a/b et de a%b est indéfini (ce qui signifie que INT_MIN%-1 est indéfini sur les systèmes de complément à 2).

Note : l'opérateur de reste ne fonctionne pas sur les types à virgule flottante, la fonction de la bibliothèque. fmod fournit cette fonctionnalité.

Logique par bit

Les expressions de l'opérateur arithmétique par bit ont la forme.

~rhs (1)
lhs&rhs (2)
lhs|rhs (3)
lhs^rhs (4)

1) bitwise NOT 2) ET par bit 3) OU binaire 4) XOR au sens des bits

où.

lhs, rhs - expressions de type entier

Tout d'abord, les opérateurs &, ^ et | effectuent des conversions arithmétiques habituelles sur les deux opérandes et l'opérateur ~ effectue des promotions d'entiers sur son seul opérande.

Ensuite, les opérateurs logiques binaires correspondants sont appliqués bitwis.e; c'est-à-dire que chaque bit du résultat est activé ou désactivé selon l'opération logique (NOT, AND, OR, ou XOR), appliquée aux bits correspondants des opérandes.

Remarque : les opérateurs de type bit sont couramment utilisés pour manipuler les ensembles de bits et les masques de bits.

Note : pour les types non signés (après promotion), l'expression ~E est équivalente à la valeur maximale représentable par le type de résultat moins la valeur originale de E.

#include#includeintmain(void){uint16_t mask =0x00f0;uint32_t a =0x12345678;printf("Value: %#x mask: %#xn""Setting bits:   %#xn""Clearing bits:  %#xn""Selecting bits: %#xn",
           a,mask,(a|mask),(a&~mask),(a&mask));}

Sortie possible :

Value:0x12345678 mask:0xf0
Setting bits:0x123456f8
Clearing bits:0x12345608
Selecting bits:0x70

Opérateurs de décalage

Les expressions de l'opérateur de décalage au sens du bit ont la forme.

lhs<<rhs (1)
lhs>>rhs (2)

1) décalage à gauche de lhs par rhs bits 2) décalage vers la droite de lhs par rhs bits

où.

lhs, rhs - expressions de type entier

D'abord, les promotions d'entiers sont effectuées, individuellement, sur chaque opérande (Note : ceci est différent des autres opérateurs arithmétiques binaires, qui effectuent tous des conversions arithmétiques habituelles). Le type du résultat est le type de lhs après la promotion.

Pour les non signés lhs, la valeur de LHS << RHS est la valeur de LHS * 2 RHS
réduit modulo la valeur maximale du type de retour plus 1 (c'est-à-dire qu'un décalage vers la gauche est effectué et que les bits qui sont décalés hors du type de destination sont rejetés). Pour les données signées lhs avec des valeurs non négatives, la valeur de LHS << RHS est LHS * 2 RHS
s'il est représentable dans le type promu de lhs, sinon le comportement est indéfini.

Pour les non signés lhs et pour les signés lhs avec des valeurs non négatives, la valeur de LHS >> RHS est la partie entière de LHS / 2 RHS
. Pour les négatifs LHSla valeur de LHS >> RHS est défini par l'implémentation. Dans la plupart des implémentations, il effectue un décalage arithmétique vers la droite (de sorte que le résultat reste négatif). Ainsi, dans la plupart des implémentations, le décalage vers la droite d'un signe LHS remplit les nouveaux bits d'ordre supérieur avec le bit de signe original (c'est-à-dire avec 0 s'il était non-négatif et 1 s'il était négatif).

Dans tous les cas, le comportement est indéfini si rhs est négatif ou est supérieur ou égal au nombre de bits dans le promu. lhs.

#includeenum{ONE=1, TWO=2};intmain(void){char c =0x10;unsignedlonglong ulong_num =0x123;printf("0x123 << 1  = %#llxn""0x123 << 63 = %#llxn"// overflow truncates high bits for unsigned numbers"0x10  << 10 = %#xn",// char is promoted to int
           ulong_num <<1, ulong_num <<63, c <<10);longlong long_num =-1000;printf("-1000 >> 1 = %lldn", long_num >> ONE);// implementation defined}

Sortie possible :

0x123<<1=0x2460x123<<63=0x80000000000000000x10<<10=0x4000-1000>>1=-500

Références :

  • Norme C11 (ISO/IEC 9899:2011) :
    • 6.5.3.3 Opérateurs arithmétiques unaires (p : 89)
    • 6.5.5 Opérateurs multiplicatifs (p : 92)
    • 6.5.6 Opérateurs additifs (p : 92-94)
    • 6.5.7 Opérateurs de décalage par bit (p : 94-95)
    • 6.5.10 Opérateur AND par bit (p : 97)
    • 6.5.11 Opérateur OU exclusif binaire (p : 98)
    • 6.5.12 Opérateur OU inclusif binaire (p : 98)
  • Norme C99 (ISO/IEC 9899:1999) :
    • 6.5.3.3 Opérateurs arithmétiques unaires (p : 79)
    • 6.5.5 Opérateurs multiplicatifs (p : 82)
    • 6.5.6 Opérateurs additifs (p : 82-84)
    • 6.5.7 Opérateurs de décalage par bit (p : 84-85)
    • 6.5.10 Opérateur AND par bit (p : 87)
    • 6.5.11 Opérateur OU exclusif binaire (p : 88)
    • 6.5.12 Opérateur OU inclusif binaire (p : 88)
  • Norme C89/C90 (ISO/IEC 9899:1990) :
    • 3.3.3.3 Opérateurs arithmétiques unaires
    • 3.3.5 Opérateurs multiplicatifs
    • 3.3.6 Opérateurs additifs
    • 3.3.7 Opérateurs de décalage par bit
    • 3.3.10 Opérateur AND par bit
    • 3.3.11 Opérateur OU exclusif binaire
    • 3.3.12 Opérateur OU inclusif binaire

Voir aussi

Précédence de l'opérateur.

Opérateurs communs
affectation incrémenter
décrémenter
arithmétique logique comparaison membre
accès
autre

a = b a += b a -= b a *= b a /= b a %= b a &= b a |= b a ^= b a <<= b a >>= b.

++a --a a++ a--

+a -a a + b a - b a * b a / b a % b ~a a & b a | b a ^ b a << b a >> b.

!a a && b a || b.

a == b a != b a < b a > b a <= b a >= b.

a[b] *a &a a->b a.b.

a(...) a, b (type) a ? : sizeof _Alignof(depuis C11).