Opérateurs en C et C++ - Operators in C and C++
Il s'agit d'une liste d' opérateurs dans les langages de programmation C et C++ . Tous les opérateurs répertoriés existent en C++ ; la colonne "Inclus dans C", indique si un opérateur est également présent dans C. Notez que C ne prend pas en charge la surcharge d'opérateur .
Lorsqu'il n'est pas surchargé, pour les opérateurs &&
, ||
, et ,
(l' opérateur virgule ), il y a un point de séquence après l'évaluation du premier opérande.
C ++ contient également la conversion de type opérateurs const_cast
, static_cast
, dynamic_cast
et reinterpret_cast
. Le formatage de ces opérateurs signifie que leur niveau de priorité est sans importance.
La plupart des opérateurs disponibles en C et C++ sont également disponibles dans d'autres langages de la famille C tels que C# , D , Java , Perl et PHP avec la même priorité, associativité et sémantique.
Table
Pour les besoins de ces tableaux, a
, b
, et c
représentent des valeurs valides (littéraux, valeurs de variables ou valeur de retour), des noms d'objet ou des lvalues, selon le cas. R
, S
et T
représente n'importe quel(s) type(s) et K
pour un type de classe ou un type énuméré.
Opérateurs arithmétiques
Tous les opérateurs arithmétiques existent en C et C++ et peuvent être surchargés en C++.
Nom de l'opérateur | Syntaxe | Exemples de prototypes C++ | ||
---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | |||
Une addition |
a + b
|
R K::operator +(S b);
|
R operator +(K a, S b);
|
|
Soustraction |
a - b
|
R K::operator -(S b);
|
R operator -(K a, S b);
|
|
Unaire plus ( promotion entière ) |
+a
|
R K::operator +();
|
R operator +(K a);
|
|
Unaire moins ( additif inverse ) |
-a
|
R K::operator -();
|
R operator -(K a);
|
|
Multiplication |
a * b
|
R K::operator *(S b);
|
R operator *(K a, S b);
|
|
Division |
a / b
|
R K::operator /(S b);
|
R operator /(K a, S b);
|
|
Modulo (reste entier) |
a % b
|
R K::operator %(S b);
|
R operator %(K a, S b);
|
|
Incrément | Préfixe |
++a
|
R& K::operator ++();
|
R& operator ++(K& a);
|
suffixe |
a++
|
R K::operator ++(int);
|
R operator ++(K& a, int);
|
|
Remarque : C++ utilise le paramètre dummy sans nom pour différencier les opérateurs d'incrémentation préfixe et suffixe.
int |
||||
Décrémenter | Préfixe |
--a
|
R& K::operator --();
|
R& operator --(K& a);
|
suffixe |
a--
|
R K::operator --(int);
|
R operator --(K& a, int);
|
|
Remarque : C++ utilise le paramètre dummy sans nom pour différencier les opérateurs de décrémentation de préfixe et de suffixe.
int |
Opérateurs de comparaison/opérateurs relationnels
Tous les opérateurs de comparaison peuvent être surchargés en C++.
Nom de l'opérateur | Syntaxe | Inclus dans C |
Exemples de prototypes | ||
---|---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | ||||
Égal à |
a == b
|
Oui |
bool K::operator ==(S const& b) const;
|
bool operator ==(K const& a, S const& b);
|
|
Pas égal à |
a != b a not_eq b
|
Oui |
bool K::operator !=(S const& b) const;
|
bool operator !=(K const& a, S const& b);
|
|
Plus grand que | a > b |
Oui |
bool K::operator >(S const& b) const;
|
bool operator >(K const& a, S const& b);
|
|
Moins que | a < b |
Oui |
bool K::operator <(S const& b) const;
|
bool operator <(K const& a, S const& b);
|
|
Plus grand ou égal à | a >= b |
Oui |
bool K::operator >=(S const& b) const;
|
bool operator >=(K const& a, S const& b);
|
|
Inférieur ou égal à | a <= b |
Oui |
bool K::operator <=(S const& b) const;
|
bool operator <=(K const& a, S const& b);
|
|
Comparaison à trois | a <=> b |
Non |
auto K::operator <=>(const S &b);
|
auto operator <=>(const K &a, const S &b);
|
|
L'opérateur a un total de 3 types de retour possibles : std::weak_ordering , std::strong_ordering et std::partial_ordering vers lesquels ils sont tous convertibles.
|
Opérateurs logiques
Tous les opérateurs logiques existent en C et C++ et peuvent être surchargés en C++, bien que la surcharge du ET logique et du OU logique soit déconseillée, car en tant qu'opérateurs surchargés, ils se comportent comme des appels de fonction ordinaires, ce qui signifie que leurs deux opérandes sont évalués, donc ils perdent leur propriété d' évaluation de court-circuit bien utilisée et attendue .
Nom de l'opérateur | Syntaxe | Exemples de prototypes C++ | ||
---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | |||
Négation logique (PAS) |
!a not a
|
bool K::operator !();
|
bool operator !(K a);
|
|
ET logique |
a && b a and b
|
bool K::operator &&(S b);
|
bool operator &&(K a, S b);
|
|
OU logique |
a || b a or b
|
bool K::operator ||(S b);
|
bool operator ||(K a, S b);
|
Opérateurs au niveau du bit
Tous les opérateurs au niveau du bit existent en C et C++ et peuvent être surchargés en C++.
Nom de l'opérateur | Syntaxe | Exemples de prototypes | ||
---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | |||
PAS au niveau du bit |
~a compl a
|
R K::operator ~();
|
R operator ~(K a);
|
|
ET au niveau du bit |
a & b a bitand b
|
R K::operator &(S b);
|
R operator &(K a, S b);
|
|
OU au niveau du bit |
a | b a bitor b
|
R K::operator |(S b);
|
R operator |(K a, S b);
|
|
XOR au niveau du bit |
a ^ b a xor b
|
R K::operator ^(S b);
|
R operator ^(K a, S b);
|
|
Décalage à gauche au niveau du bit |
a << b
|
R K::operator <<(S b);
|
R operator <<(K a, S b);
|
|
Décalage à droite au niveau du bit |
a >> b
|
R K::operator >>(S b);
|
R operator >>(K a, S b);
|
Opérateurs d'affectation
Toutes les expressions d'affectation existent en C et C++ et peuvent être surchargées en C++.
Pour les opérateurs donnés, la sémantique de l'expression d'affectation combinée intégrée a ⊚= b
est équivalente à a = a ⊚ b
, sauf qu'elle a
n'est évaluée qu'une seule fois.
Nom de l'opérateur | Syntaxe | Exemples de prototypes C++ | |
---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | ||
Affectation directe |
a = b
|
R& K::operator =(S b);
|
N / A |
Affectation d'ajout |
a += b
|
R& K::operator +=(S b);
|
R& operator +=(K& a, S b);
|
Affectation de soustraction |
a -= b
|
R& K::operator -=(S b);
|
R& operator -=(K& a, S b);
|
Affectation de multiplication |
a *= b
|
R& K::operator *=(S b);
|
R& operator *=(K& a, S b);
|
Affectation divisionnaire |
a /= b
|
R& K::operator /=(S b);
|
R& operator /=(K& a, S b);
|
Affectation modulo |
a %= b
|
R& K::operator %=(S b);
|
R& operator %=(K& a, S b);
|
Affectation ET au niveau du bit |
a &= b a and_eq b
|
R& K::operator &=(S b);
|
R& operator &=(K& a, S b);
|
Affectation OR au niveau du bit |
a |= b a or_eq b
|
R& K::operator |=(S b);
|
R& operator |=(K& a, S b);
|
Affectation XOR au niveau du bit |
a ^= b a xor_eq b
|
R& K::operator ^=(S b);
|
R& operator ^=(K& a, S b);
|
Affectation de décalage à gauche au niveau du bit |
a <<= b
|
R& K::operator <<=(S b);
|
R& operator <<=(K& a, S b);
|
Affectation de décalage à droite au niveau du bit |
a >>= b
|
R& K::operator >>=(S b);
|
R& operator >>=(K& a, S b);
|
Opérateurs membres et pointeurs
Nom de l'opérateur | Syntaxe | Peut surcharger en C++ | Inclus dans C |
Exemples de prototypes C++ | ||
---|---|---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | |||||
Indice |
a[b]
|
Oui | Oui |
R& K::operator [](S b); |
N / A | |
Indirection ("objet pointé par un ") | *a |
Oui | Oui |
R& K::operator *();
|
R& operator *(K a);
|
|
Adresse-de ("adresse d' un ") | &a |
Oui | Oui |
R* K::operator &();
|
R* operator &(K a);
|
|
Déréférencement de structure ("membre b de l'objet pointé par a ") | a->b |
Oui | Oui |
R* K::operator ->(); |
N / A | |
Référence de structure ("membre b de l'objet a ") | a.b |
Non | Oui | N / A | ||
Membre sélectionné par le pointeur vers le membre b de l'objet pointé par un | a->*b |
Oui | Non |
R& K::operator ->*(S b);
|
R& operator ->*(K a, S b);
|
|
Membre de l'objet a sélectionné par pointeur sur membre b | a.*b |
Non | Non | N / A |
Autres opérateurs
Nom de l'opérateur | Syntaxe | Peut surcharger en C++ | Inclus dans C |
Exemples de prototypes | ||
---|---|---|---|---|---|---|
En tant que membre de K | En dehors des définitions de classe | |||||
Appel de fonction Voir Objet fonction . |
a(a1, a2)
|
Oui | Oui |
R K::operator ()(S a, T b, ...);
|
N / A | |
Virgule | a, b |
Oui | Oui |
R K::operator ,(S b);
|
R operator ,(K a, S b);
|
|
Ternaire conditionnel | a ? b : c |
Non | Oui | N / A | ||
Résolution de la portée | a::b |
Non | Non | N / A | ||
Littéraux définis par l'utilisateur depuis C++11 |
"a"_b |
Oui | Non | N / A |
R operator "" _b(T a)
|
|
Taille de |
sizeof(a) sizeof(type)
|
Non | Oui | N / A | ||
Taille du pack de paramètres depuis C++11 |
sizeof...(Args) |
Non | Non | N / A | ||
Alignof depuis C++11 |
alignof(type) ou _Alignof(type)
|
Non | Oui | N / A | ||
Identification du type |
typeid(a) typeid(type)
|
Non | Non | N / A | ||
Conversion (fonte de style C) | (type)a |
Oui | Oui |
K::operator R();
|
N / A | |
Conversion | type(a) |
Non | Non | Remarque : se comporte comme const_cast/static_cast/reinterpret_cast | ||
conversion statique_cast | static_cast<type>(a) |
Oui | Non |
K::operator R(); explicit K::operator R(); depuis C++11
|
N / A | |
Remarque : pour les conversions définies par l'utilisateur, le type de retour correspond implicitement et nécessairement au nom de l'opérateur. | ||||||
conversion de distribution dynamique | dynamic_cast<type>(a) |
Non | Non | N / A | ||
conversion const_cast | const_cast<type>(a) |
Non | Non | N / A | ||
conversion reinterpret_cast | reinterpret_cast<type>(a) |
Non | Non | N / A | ||
Allouer du stockage | new type |
Oui | Non |
void* K::operator new(size_t x);
|
void* operator new(size_t x);
|
|
Allouer le stockage (tableau) | new type[n] |
Oui | Non |
void* K::operator new[](size_t a);
|
void* operator new[](size_t a);
|
|
Désallouer le stockage | delete a |
Oui | Non |
void K::operator delete(void* a);
|
void operator delete(void* a);
|
|
Désallouer le stockage (tableau) | delete[] a |
Oui | Non |
void K::operator delete[](void* a);
|
void operator delete[](void* a);
|
|
Vérification des exceptions depuis C++11 |
noexcept(a) |
Non | Non | N / A |
Remarques:
Priorité de l'opérateur
Ce qui suit est un tableau qui répertorie la priorité et l' associativité de tous les opérateurs dans les langages C et C++ (lorsque les opérateurs existent également en Java , Perl , PHP et de nombreux autres langages récents, la priorité est la même que celle donnée). Les opérateurs sont répertoriés de haut en bas, par ordre décroissant. La priorité décroissante fait référence à la priorité du regroupement d'opérateurs et d'opérandes. Considérant une expression, un opérateur qui est répertorié sur une ligne sera groupé avant tout opérateur qui est répertorié sur une ligne plus loin en dessous. Les opérateurs qui se trouvent dans la même cellule (il peut y avoir plusieurs rangées d'opérateurs répertoriés dans une cellule) sont regroupés avec la même priorité, dans la direction donnée. La priorité d'un opérateur n'est pas affectée par la surcharge.
La syntaxe des expressions en C et C++ est spécifiée par une grammaire de structure de phrase . Le tableau donné ici a été déduit de la grammaire. Pour la norme ISO C 1999, la section 6.5.6 note 71 indique que la grammaire C fournie par la spécification définit la priorité des opérateurs C, et indique également que la priorité des opérateurs résultant de la grammaire suit étroitement l'ordre des sections de la spécification :
" La syntaxe [C] [c'est-à-dire la grammaire] spécifie la priorité des opérateurs dans l'évaluation d'une expression, qui est la même que l'ordre des principaux paragraphes de ce paragraphe, la priorité la plus élevée en premier."
Une table de priorité, bien que généralement adéquate, ne peut pas résoudre quelques détails. En particulier, notez que l' opérateur ternaire autorise toute expression arbitraire comme opérande intermédiaire, bien qu'il soit répertorié comme ayant une priorité plus élevée que les opérateurs d'affectation et de virgule. Ainsi a ? b, c : d
est interprété comme a ? (b, c) : d
, et non comme insignifiant (a ? b), (c : d)
. Ainsi, l'expression au milieu de l'opérateur conditionnel (entre ?
et :
) est analysée comme si elle était entre parenthèses. Notez également que le résultat immédiat sans parenthèses d'une expression de transtypage C ne peut pas être l'opérande de sizeof
. Par conséquent, sizeof (int) * x
est interprété comme (sizeof(int)) * x
et non sizeof ((int) * x)
.
Priorité | Opérateur | La description | L'associativité |
---|---|---|---|
1
plus haut |
::
|
Résolution de la portée (C++ uniquement) | Rien |
2 |
++
|
Incrément de suffixe | De gauche à droite |
--
|
Décrément de suffixe | ||
()
|
Appel de fonction | ||
[]
|
Abonnement de tableau | ||
.
|
Sélection d'éléments par référence | ||
->
|
Sélection d'éléments par pointeur | ||
typeid()
|
Informations sur le type d' exécution (C++ uniquement) (voir typeid ) | ||
const_cast
|
Type cast (C++ uniquement) (voir const_cast ) | ||
dynamic_cast
|
Cast de type (C++ uniquement) (voir cast dynamique ) | ||
reinterpret_cast
|
Type cast (C++ uniquement) (voir reinterpret_cast ) | ||
static_cast
|
Type cast (C++ uniquement) (voir static_cast ) | ||
3 |
++
|
Incrément de préfixe | De droite à gauche |
--
|
Décrément de préfixe | ||
+
|
Unaire plus | ||
-
|
Unaire moins | ||
!
|
NON logique | ||
~
|
PAS au niveau du bit (complément à un) | ||
(type)
|
Type de fonte | ||
*
|
Indirection (déréférencement) | ||
&
|
Adresse de | ||
sizeof
|
Taille de | ||
_Alignof
|
Exigence d'alignement (depuis C11) | ||
new , new[]
|
Allocation dynamique de mémoire (C++ uniquement) | ||
delete , delete[]
|
Désallocation dynamique de mémoire (C++ uniquement) | ||
4 |
.*
|
Pointeur vers le membre (C++ uniquement) | De gauche à droite |
->*
|
Pointeur vers le membre (C++ uniquement) | ||
5 |
*
|
Multiplication | De gauche à droite |
/
|
Division | ||
%
|
Modulo (reste) | ||
6 |
+
|
Une addition | De gauche à droite |
-
|
Soustraction | ||
7 |
<<
|
Décalage à gauche au niveau du bit | De gauche à droite |
>>
|
Décalage à droite au niveau du bit | ||
8 |
<=>
|
Comparaison à trois (Introduit dans C++20 - C++ uniquement) | De gauche à droite |
9 |
<
|
Moins que | De gauche à droite |
<=
|
Inférieur ou égal à | ||
>
|
Plus grand que | ||
>=
|
Plus grand ou égal à | ||
dix |
==
|
Égal à | De gauche à droite |
!=
|
Pas égal à | ||
11 |
&
|
ET au niveau du bit | De gauche à droite |
12 |
^
|
Bitwise XOR (exclusif ou) | De gauche à droite |
13 |
|
|
OU au niveau du bit (ou inclus) | De gauche à droite |
14 |
&&
|
ET logique | De gauche à droite |
15 |
||
|
OU logique | De gauche à droite |
16 |
?:
|
Ternaire conditionnel (voir ?: ) | De droite à gauche |
=
|
Affectation directe | ||
+=
|
Affectation par somme | ||
-=
|
Affectation par différence | ||
*=
|
Affectation par produit | ||
/=
|
Affectation par quotient | ||
%=
|
Affectation par reliquat | ||
<<=
|
Affectation par décalage à gauche au niveau du bit | ||
>>=
|
Affectation par décalage à droite au niveau du bit | ||
&=
|
Affectation par ET au niveau du bit | ||
^=
|
Affectation par bit à bit XOR | ||
|=
|
Affectation par OU au niveau du bit | ||
throw
|
Opérateur Throw (lancement d'exceptions, C++ uniquement) | ||
17
le plus bas |
,
|
Virgule | De gauche à droite |
Remarques
La table de priorité détermine l'ordre de liaison dans les expressions chaînées, lorsqu'il n'est pas expressément spécifié par des parenthèses.
- Par exemple,
++x*3
est ambigu sans règle(s) de priorité. La table de précédence nous dit que : x est « lié » plus étroitement à ++ qu'à * , de sorte que tout ce que ++ fait (maintenant ou plus tard—voir ci-dessous), il le fait UNIQUEMENT à x (et non àx*3
) ; il est équivalent à (++x
,x*3
). - De même, avec
3*x++
, où bien que le post-fix ++ soit conçu pour agir APRÈS que l'expression entière ait été évaluée, la table de priorité indique clairement que SEUL x est incrémenté (et PAS3*x
). En fait, l'expression (tmp=x++
,3*tmp
) est évaluée avec tmp étant une valeur temporaire. Il est fonctionnellement équivalent à quelque chose comme (tmp=3*x
,++x
,tmp
).
- En faisant abstraction de la question de préséance ou de liaison, considérons le diagramme ci-dessus pour l'expression 3+2*y[i]++. Le travail du compilateur consiste à résoudre le diagramme en une expression, dans laquelle plusieurs opérateurs unaires (appelez-les 3+( . ), 2*( . ), ( . )++ et ( . )[ i ]) sont en compétition pour lier jouet. L'ordre de priorité du tableau résout la sous-expression finale sur laquelle chacun agit : ( . )[ i ] agit uniquement sur y, ( . )++ agit uniquement sur y[i], 2*( . ) agit uniquement sur y[ i]++ et 3+( . ) agit 'seulement' sur 2*((y[i])++). Il est important de noter que la sous-expression sur laquelle chaque opérateur agit est claire dans la table de précédence, mais QUAND chaque opérateur agit n'est pas résolu par la table de précédence ; dans cet exemple, l'opérateur ( . )++ agit uniquement sur y[i] par les règles de précédence mais les niveaux de liaison à eux seuls n'indiquent pas le timing du suffixe ++ (l'opérateur ( . )++ n'agit qu'après y[i ] est évalué dans l'expression).
De nombreux opérateurs contenant des séquences de plusieurs caractères reçoivent des "noms" construits à partir du nom d'opérateur de chaque caractère. Par exemple, +=
et -=
sont souvent appelés plus égal(s) et moins égal(s) , au lieu des plus verbeux « affectation par addition » et « affectation par soustraction ». La liaison des opérateurs en C et C++ est spécifiée (dans les normes correspondantes) par une grammaire de langage factorisée, plutôt que par une table de précédence. Cela crée des conflits subtils. Par exemple, en C, la syntaxe d'une expression conditionnelle est :
logical-OR-expression ? expression : conditional-expression
alors qu'en C++ c'est :
logical-OR-expression ? expression : assignment-expression
D'où l'expression :
e = a < d ? a++ : a = d
est analysé différemment dans les deux langues. En C, cette expression est une erreur de syntaxe, car la syntaxe d'une expression d'affectation en C est :
unary-expression '=' assignment-expression
En C++, il est analysé comme :
e = (a < d ? a++ : (a = d))
qui est une expression valide.
Si vous souhaitez utiliser une virgule en tant qu'opérateur dans un seul argument de fonction, une affectation de variable ou une autre liste séparée par des virgules, vous devez utiliser des parenthèses, par exemple :
int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
Critique de la priorité des opérateurs de bits et d'égalité
La priorité des opérateurs logiques au niveau du bit a été critiquée. Conceptuellement, & et | sont des opérateurs arithmétiques comme * et +.
L'expression est syntaxiquement analysée comme alors que l'expression est analysée comme . Cela nécessite que les parenthèses soient utilisées plus souvent qu'elles ne le feraient autrement.
a & b == 7
a & (b == 7)
a + b == 7
(a + b) == 7
Historiquement, il n'y avait pas de distinction syntaxique entre les opérateurs binaires et logiques. En BCPL , B et au début du C, les opérateurs n'existaient pas. Au lieu de cela, ils avaient une signification différente selon qu'ils sont utilisés dans un « contexte de valeur de vérité » (c'est-à-dire lorsqu'une valeur booléenne était attendue, par exemple lorsqu'elle se comportait comme un opérateur logique, mais qu'elle se comportait comme une valeur au niveau du bit). Il a été conservé afin de conserver une rétrocompatibilité avec les installations existantes.
&& ||
& |
if (a==b & c) {...}
c = a & b
De plus, en C++ (et dans les versions ultérieures de C), les opérations d'égalité, à l'exception de l'opérateur de comparaison à trois voies, produisent des valeurs de type bool qui sont conceptuellement un seul bit (1 ou 0) et en tant que telles n'appartiennent pas correctement à " " opérations.
Synonymes de l'opérateur C++
C++ définit certains mots-clés pour agir comme des alias pour un certain nombre d'opérateurs :
Mot-clé | Opérateur |
---|---|
and |
&&
|
and_eq |
&=
|
bitand |
&
|
bitor |
|
|
compl |
~
|
not |
!
|
not_eq |
!=
|
or |
||
|
or_eq |
|=
|
xor |
^
|
xor_eq |
^=
|
Ceux-ci peuvent être utilisés exactement de la même manière que les symboles de ponctuation qu'ils remplacent, car ce ne sont pas le même opérateur sous un nom différent, mais plutôt de simples remplacements de jetons pour le nom (chaîne de caractères) de l'opérateur respectif. Cela signifie que les expressions (a > 0 and not flag)
et (a > 0 && !flag)
ont des significations identiques. Cela signifie également que, par exemple, le bitand
mot-clé peut être utilisé pour remplacer non seulement l' opérateur au niveau du bit et mais aussi l' opérateur adresse de , et il peut même être utilisé pour spécifier des types de référence (par exemple, int bitand ref = n
). La spécification ISO C tient compte de ces mots clés en tant que macros de préprocesseur dans le fichier d'en-tête iso646.h
. Pour la compatibilité avec C, C++ fournit l'en-tête ciso646
, dont l'inclusion n'a aucun effet.
Voir également
- Opérations au niveau des bits en C
- Manipulation de bits
- Opérateur logique
- Algèbre booléenne (logique)
- Tableau des symboles logiques
- Digrammes et trigraphes en C et en C++
Les références
Liens externes
- "Opérateurs", référence C++ (wiki).
- C Priorité de l'opérateur
- Opérateurs d'incrémentation et de décrémentation de Postfix : ++ et -- (réseau de développeurs), Microsoft.