Namespaces
Variants

Other operators

From cppreference.net

Une collection d'opérateurs qui ne s'inscrivent dans aucune des autres catégories majeures.

Opérateur Nom de l'opérateur Exemple Description
( ... ) Appel de fonction f ( ... ) Appelle la fonction f (), avec zéro ou plusieurs arguments
, Opérateur virgule a, b Évalue l'expression a , ignore sa valeur de retour et complète tous les effets secondaires, puis évalue l'expression b , renvoyant le type et le résultat de cette évaluation
( type ) Conversion de type ( type ) a Convertit le type de a en type
? : Opérateur conditionnel a ? b : c Si a est logiquement vrai (n'évalue pas à zéro) alors évalue l'expression b , sinon évalue l'expression c
sizeof Opérateur sizeof sizeof a La taille en octets de a
_Alignof
(depuis C11)
Opérateur _Alignof _Alignof ( type ) L'alignement requis pour type
typeof Opérateurs typeof typeof ( a ) Le type de a

Table des matières

Appel de fonction

L'expression d'appel de fonction a la forme

expression ( liste-arguments  (optionnel) )

expression - toute expression de type pointeur-vers-fonction (après conversions de lvalue )
argument-list - liste d'expressions séparées par des virgules (qui ne peuvent pas être des opérateurs virgule) de tout type d'objet complet. Peut être omise lors de l'appel de fonctions qui ne prennent aucun argument.

Le comportement de l'expression d'appel de fonction dépend de si le prototype de la fonction appelée est dans la portée au point d'appel.

Appel à une fonction avec un prototype

1) Le nombre de paramètres doit être égal au nombre d'arguments (sauf si le paramètre ellipsis est utilisé).
2) Le type de chaque paramètre doit être un type tel qu'il existe une conversion implicite comme par affectation qui convertit le type non qualifié de l'argument correspondant vers le type du paramètre.
De plus, pour chaque paramètre de type tableau qui utilise le mot-clé static entre [ et ] , l'expression d'argument doit désigner un pointeur vers l'élément d'un tableau ayant au moins autant d'éléments que spécifié dans l'expression de taille du paramètre.
(depuis C99)
4) Assignment est effectué pour copier la valeur de chaque argument dans le paramètre de fonction correspondant, en ignorant tout qualificateur de type sur le type du paramètre et ses éléments ou membres éventuellement récursifs, s'il y en a (note : la fonction peut modifier ses paramètres, et ces modifications n'affectent pas les arguments ; les appels de fonction en C sont uniquement par valeur).
5) La fonction est exécutée, et la valeur qu'elle retourne devient la valeur de l'expression d'appel de fonction (si la fonction retourne void, l'expression d'appel de fonction est une expression void)
void f(char* p, int x) {}
int main(void)
{
    f("abc", 3.14); // array to pointer and float to int conversions
}

Appel à une fonction sans prototype

2) Les promotions d'arguments par défaut sont effectuées sur chaque expression d'argument.
3) Une affectation est réalisée pour copier la valeur de chaque argument vers le paramètre de fonction correspondant, en ignorant tout qualificateur de type sur le type du paramètre et ses éléments ou membres éventuellement récursifs, s'il y en a.
4) La fonction est exécutée, et la valeur qu'elle retourne devient la valeur de l'expression d'appel de fonction (si la fonction retourne void, l'expression d'appel de fonction est une expression void)
void f(); // no prototype
int main(void)
{
    f(1, 1.0f); // UB unless f is defined to take an int and a double
}
void f(int a, double c) {}

Le comportement d'un appel de fonction sans prototype est indéfini si

  • le nombre d'arguments ne correspond pas au nombre de paramètres.
  • les types promus des arguments ne sont pas compatibles avec les types promus des paramètres, sauf que
  • les versions signées et non signées du même type entier sont considérées comme compatibles si la valeur de l'argument est représentable par les deux types.
  • les pointeurs vers void et les pointeurs vers des types caractères (éventuellement qualifiés cvr) sont considérés comme compatibles
(jusqu'à C23)

Notes

Les évaluations de expression qui désigne la fonction à appeler et de tous les arguments sont non-séquencées les unes par rapport aux autres (mais il y a un point de séquence avant que le corps de la fonction ne commence à s'exécuter)

(*pf[f1()]) (f2(), f3() + f4()); // f1, f2, f3, f4 peuvent être appelées dans n'importe quel ordre

Bien que l'appel de fonction ne soit défini que pour les pointeurs vers des fonctions, il fonctionne avec les désignateurs de fonction grâce à la conversion implicite fonction-vers-pointeur .

int f(void) { return 1; }
int (*pf)(void) = f;
int main(void)
{
    f();    // convertit f en pointeur, puis appelle
    (&f)(); // crée un pointeur vers fonction, puis appelle
    pf();    // appelle la fonction
    (*pf)(); // obtient le désignateur de fonction, convertit en pointeur, puis appelle
    (****f)(); // convertit en pointeur, obtient la fonction, répète 4x, puis appelle
    (****pf)(); // également OK
}

Les fonctions qui ignorent les arguments inutilisés, telles que printf , doivent être appelées avec un prototype dans la portée (le prototype de ces fonctions utilise nécessairement le paramètre ellipses de fin ) pour éviter d'invoquer un comportement indéfini.

La formulation actuelle de la norme concernant la sémantique de préparation des paramètres de fonction est défectueuse, car elle spécifie que les paramètres sont assignés à partir des arguments lors de l'appel, ce qui rejette incorrectement les types de paramètres ou membres qualifiés const, et applique inappropriément la sémantique de volatile qui est irréalisable pour les paramètres de fonction sur de nombreuses plateformes. Un rapport de défaut post-C11 DR427 a proposé de modifier cette sémantique d'assignation en initialisation, mais a été clos comme n'étant pas un défaut.

Une expression d'appel de fonction où expression consiste entièrement en un identifiant et que cet identifiant n'est pas déclaré agit comme si l'identifiant était déclaré comme

extern int identifier(); // returns int and has no prototype

Ainsi le programme complet suivant est valide en C89 :

main()
{
    int n = atoi("123"); // implicitly declares atoi as int atoi()
}
(jusqu'à C99)

Opérateur virgule

L'expression de l'opérateur virgule a la forme

lhs , rhs

lhs - toute expression
rhs - toute expression autre qu'un autre opérateur virgule (en d'autres termes, l' associativité de l'opérateur virgule est de gauche à droite)

D'abord, l'opérande gauche, lhs , est évalué et sa valeur résultante est ignorée.

Ensuite, un point de séquence intervient, de sorte que tous les effets secondaires de lhs soient terminés.

Ensuite, l'opérande droit, rhs , est évalué et son résultat est retourné par l'opérateur virgule en tant que non-lvalue .

Notes

Le type du lhs peut être void (c'est-à-dire qu'il peut s'agir d'un appel à une fonction qui retourne void , ou il peut s'agir d'une expression cast vers void )

L'opérateur virgule peut être une lvalue en C++, mais jamais en C

L'opérateur virgule peut renvoyer une structure (les seules autres expressions qui renvoient des structures sont les littéraux composés, les appels de fonction, les assignations et l'opérateur conditionnel)

Dans les contextes suivants, l'opérateur virgule ne peut pas apparaître au niveau supérieur d'une expression car la virgule a une signification différente :

Si l'opérateur virgule doit être utilisé dans un tel contexte, il doit être mis entre parenthèses :

// int n = 2,3; // erreur, la virgule est supposée commencer le déclarateur suivant
// int a[2] = {1,2,3}; // erreur : plus d'initialiseurs que d'éléments
int n = (2,3), a[2] = {(1,2),3}; // OK
f(a, (t=3, t+2), c); // OK, d'abord, stocke 3 dans t, puis appelle f avec trois arguments

L'opérateur virgule de premier niveau est également interdit dans les bornes des tableaux

// int a[2,3]; // erreur
int a[(2,3)]; // OK, tableau VLA de taille 3 (VLA car (2,3) n'est pas une expression constante)

L'opérateur virgule n'est pas autorisé dans les expressions constantes , qu'il soit au niveau supérieur ou non

// static int n = (1,2); // Erreur : une expression constante ne peut pas appeler l'opérateur virgule

Opérateur de cast

Voir cast operator

Opérateur conditionnel

L'expression de l'opérateur conditionnel a la forme

condition ? expression-vraie : expression-fausse

condition - une expression de type scalaire
expression-true - l'expression qui sera évaluée si la condition est différente de zéro
expression-false - l'expression qui sera évaluée si la condition est égale à zéro

Seules les expressions suivantes sont autorisées comme expression-true et expression-false

(depuis C23)
  • une expression est un pointeur et l'autre est la constante de pointeur nul (telle que NULL ) ou une valeur nullptr_t (depuis C23)
  • une expression est un pointeur vers objet et l'autre est un pointeur vers void (éventuellement qualifié)
1) Premièrement, évalue condition . Il y a un sequence point après cette évaluation.
2) Si le résultat de condition est différent de zéro, exécute expression-true , sinon exécute expression-false
3) Effectue une conversion du résultat de l'évaluation vers le type commun , défini comme suit :
1) si les expressions ont un type arithmétique, le type commun est le type après les usual arithmetic conversions
2) si les expressions ont un type struct/union, le type commun est ce type struct/union
3) si les deux expressions sont de type void, l'expression complète de l'opérateur conditionnel est une expression void
4) si l'un est un pointeur et l'autre est une constante de pointeur nul ou une valeur nullptr_t (depuis C23) , le type est celui de ce pointeur
5) si les deux sont des pointeurs, le résultat est le pointeur vers le type qui combine les qualificatifs cvr des deux types pointés (c'est-à-dire, si l'un est const int * et l'autre est volatile int * , le résultat est const volatile int * ), et si les types étaient différents, le type pointé est le type composite .
6) si l'un est un pointeur vers void, le résultat est un pointeur vers void avec les qualificateurs cvr combinés
7) si les deux ont le type nullptr_t , le type commun est également nullptr_t
(depuis C23)
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))
// si x est une Expression Constante Entière alors la macro se développe en
sizeof(*(1 ? NULL : (int *) 1))  // (void *)((x)*0l)) -> NULL
// selon le point (4) cela se convertit ensuite en
sizeof(int)
// si x n'est pas une Expression Constante Entière alors la macro se développe en
// selon le point (6)
(sizeof(*(void *)(x))           // Erreur due au type incomplet

Notes

L'opérateur conditionnel n'est jamais une expression lvalue , bien qu'il puisse retourner des objets de type struct/union. Les seules autres expressions pouvant retourner des structures sont l'affectation , la virgule , l'appel de fonction , et le littéral composé .

Notez qu'en C++, il peut s'agir d'une expression lvalue.

Voir la précédence des opérateurs pour les détails sur la précédence relative de cet opérateur et de l'affectation.

L'opérateur conditionnel a une associativité de droite à gauche, ce qui permet l'enchaînement

#include <assert.h>
enum vehicle { bus, airplane, train, car, horse, feet };
enum vehicle choose(char arg)
{
    return arg == 'B' ? bus      :
           arg == 'A' ? airplane :
           arg == 'T' ? train    :
           arg == 'C' ? car      :
           arg == 'H' ? horse    :
                        feet     ;
}
int main(void)
{
    assert(choose('H') == horse && choose('F') == feet);
}

sizeof opérateur

Voir sizeof operator

_Alignof opérateur

Voir opérateur _Alignof

typeof opérateurs

Voir opérateurs typeof

Références

  • Norme C23 (ISO/CEI 9899:2024) :
  • 6.5.2.2 Appels de fonction (p: TBD)
  • 6.5.3.4 Opérateurs sizeof et _Alignof (p: TBD)
  • 6.5.4 Opérateurs de cast (p: TBD)
  • 6.5.15 Opérateur conditionnel (p: TBD)
  • 6.5.17 Opérateur virgule (p: TBD)
  • 6.7.3.5 Spécificateurs typeof (p: 115-118)
  • Norme C17 (ISO/CEI 9899:2018) :
  • 6.5.2.2 Appels de fonction (p: 58-59)
  • 6.5.3.4 Opérateurs sizeof et _Alignof (p: 64-65)
  • 6.5.4 Opérateurs de cast (p: 65-66)
  • 6.5.15 Opérateur conditionnel (p: 71-72)
  • 6.5.17 Opérateur virgule (p: 75)
  • Norme C11 (ISO/CEI 9899:2011) :
  • 6.5.2.2 Appels de fonction (p: 81-82)
  • 6.5.3.4 Opérateurs sizeof et _Alignof (p: 90-91)
  • 6.5.4 Opérateurs de cast (p: 91)
  • 6.5.15 Opérateur conditionnel (p: 100)
  • 6.5.17 Opérateur virgule (p: 105)
  • Norme C99 (ISO/CEI 9899:1999) :
  • 6.5.2.2 Appels de fonction (p. 71-72)
  • 6.5.3.4 L'opérateur sizeof (p. 80-81)
  • 6.5.4 Opérateurs de cast (p. 81)
  • 6.5.15 Opérateur conditionnel (p. 90-91)
  • 6.5.17 Opérateur virgule (p. 94)
  • Norme C89/C90 (ISO/CEI 9899:1990) :
  • 3.3.2.2 Appels de fonction
  • 3.3.3.4 L'opérateur sizeof
  • 3.3.4 Opérateurs de cast
  • 3.3.15 Opérateur conditionnel
  • 3.3.17 Opérateur virgule

Voir aussi

Opérateurs courants
affectation incrémentation
décrémentation
arithmétique logique comparaison accès membre autres

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
a ? b : c
sizeof


_Alignof
(depuis C11)
(jusqu'à C23)

alignof
(depuis C23)

Documentation C++ pour Autres opérateurs