Namespaces
Variants

Other operators

From cppreference.net

Una colección de operadores que no encajan en ninguna de las otras categorías principales.

Operador Nombre del operador Ejemplo Descripción
( ... ) llamada de función f ( ... ) llama a la función f (), con cero o más argumentos
, operador coma a, b evalúa la expresión a , ignora su valor de retorno y completa cualquier efecto secundario, luego evalúa la expresión b , devolviendo el tipo y el resultado de esta evaluación
( type ) conversión de tipo ( type ) a convierte el tipo de a a type
? : operador condicional a ? b : c si a es lógicamente verdadero (no se evalúa a cero) entonces evalúa la expresión b , de lo contrario evalúa la expresión c
sizeof operador sizeof sizeof a el tamaño en bytes de a
_Alignof
(desde C11)
operador _Alignof _Alignof ( type ) la alineación requerida de type
typeof operadores typeof typeof ( a ) el tipo de a

Contenidos

Llamada de función

La expresión de llamada a función tiene la forma

expresión ( lista-de-argumentos  (opcional) )

donde

expression - cualquier expresión de tipo puntero-a-función (después de las conversiones de lvalue )
argument-list - lista separada por comas de expresiones (que no pueden ser operadores coma) de cualquier tipo de objeto completo. Puede omitirse al llamar funciones que no toman argumentos.

El comportamiento de la expresión de llamada a función depende de si el prototipo de la función que se llama está en alcance en el punto de la llamada.

Llamada a una función con un prototipo

1) El número de parámetros debe ser igual al número de argumentos (a menos que se utilice el parámetro de elipsis).
2) El tipo de cada parámetro debe ser un tipo tal que conversión implícita como por asignación exista que convierta el tipo no calificado del argumento correspondiente al tipo del parámetro.
Adicionalmente, para cada parámetro de tipo array que utilice la palabra clave static entre [ y ] , la expresión de argumento debe designar un puntero al elemento de un array con al menos tantos elementos como se especifica en la expresión de tamaño del parámetro.
(desde C99)
3) Los argumentos son evaluados en orden no especificado y sin secuenciación .
4) Asignación se realiza para copiar el valor de cada argumento al parámetro de función correspondiente, ignorando cualquier calificador de tipo en el tipo de parámetro y sus elementos o miembros posiblemente recursivos, si los hay (nota: la función puede modificar sus parámetros, y esos cambios no afectan los argumentos; las llamadas a funciones en C son solo por valor).
5) La función se ejecuta, y el valor que devuelve se convierte en el valor de la expresión de llamada a función (si la función devuelve void, la expresión de llamada a función es una expresión void)
void f(char* p, int x) {}
int main(void)
{
    f("abc", 3.14); // array to pointer and float to int conversions
}

Llamada a una función sin prototipo

1) Los argumentos son evaluados en orden no especificado y sin secuenciación .
2) Promociones de argumentos por defecto se realizan en cada expresión de argumento.
3) Asignación se realiza para copiar el valor de cada argumento al parámetro de función correspondiente, ignorando cualquier calificador de tipo en el tipo del parámetro y sus posibles elementos o miembros recursivos, si los hay.
4) La función se ejecuta, y el valor que devuelve se convierte en el valor de la expresión de llamada a función (si la función devuelve void, la expresión de llamada a función es una expresión 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) {}

El comportamiento de una llamada a función sin prototipo es indefinido si

  • el número de argumentos no coincide con el número de parámetros.
  • los tipos promocionados de los argumentos no son compatibles con los tipos promocionados de los parámetros excepto que
  • las versiones con signo y sin signo del mismo tipo entero se consideran compatibles si el valor del argumento es representable por ambos tipos.
  • punteros a void y punteros a tipos carácter (posiblemente calificados cvr) se consideran compatibles
(hasta C23)

Notas

Las evaluaciones de expression que designa la función a llamar y todos los argumentos están sin secuenciar entre sí (pero hay un punto de secuencia antes de que comience la ejecución del cuerpo de la función)

(*pf[f1()]) (f2(), f3() + f4()); // f1, f2, f3, f4 pueden ser llamadas en cualquier orden

Aunque la llamada a función solo está definida para punteros a funciones, funciona con designadores de función debido a la conversión implícita de función a puntero .

int f(void) { return 1; }
int (*pf)(void) = f;
int main(void)
{
    f();    // convertir f a puntero, luego llamar
    (&f)(); // crear un puntero a función, luego llamar
    pf();    // llamar la función
    (*pf)(); // obtener el designador de función, convertir a puntero, luego llamar
    (****f)(); // convertir a puntero, obtener la función, repetir 4x, luego llamar
    (****pf)(); // también correcto
}

Las funciones que ignoran argumentos no utilizados, como printf , deben ser llamadas con un prototipo en alcance (el prototipo de dichas funciones necesariamente utiliza el parámetro de puntos suspensivos finales ) para evitar invocar comportamiento indefinido.

La redacción actual estándar de la semántica de preparación de parámetros de función es defectuosa, porque especifica que los parámetros se asignan desde argumentos durante la llamada, lo cual rechaza incorrectamente tipos de parámetros o miembros calificados como const, y aplica inapropiadamente la semántica de volatile que es inimplementable para parámetros de función en muchas plataformas. Un reporte de defecto post-C11 DR427 propuso cambiar dicha semántica de asignación a inicialización, pero fue cerrado como no-defecto.

Una expresión de llamada a función donde expression consiste completamente en un identificador y ese identificador no está declarado actúa como si el identificador se declarara como

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

Por lo tanto, el siguiente programa completo es válido en C89:

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

Operador coma

La expresión del operador coma tiene la forma

lhs , rhs

donde

lhs - cualquier expresión
rhs - cualquier expresión excepto otro operador coma (en otras palabras, la asociatividad del operador coma es de izquierda a derecha)

Primero, el operando izquierdo, lhs , es evaluado y su valor resultante es descartado.

Entonces, tiene lugar un punto de secuencia , de modo que todos los efectos secundarios de lhs se completan.

Luego, el operando derecho, rhs , es evaluado y su resultado es devuelto por el operador coma como un no-lvalue .

Notas

El tipo del lhs puede ser void (es decir, puede ser una llamada a una función que devuelve void , o puede ser una expresión cast a void )

El operador coma puede ser lvalue en C++, pero nunca en C

El operador coma puede devolver una estructura (las únicas otras expresiones que devuelven estructuras son los literales compuestos, las llamadas a funciones, las asignaciones y el operador condicional)

En los siguientes contextos, el operador coma no puede aparecer en el nivel superior de una expresión porque la coma tiene un significado diferente:

Si el operador coma debe utilizarse en tal contexto, debe ir entre paréntesis:

// int n = 2,3; // error, se asume que la coma comienza el siguiente declarador
// int a[2] = {1,2,3}; // error: más inicializadores que elementos
int n = (2,3), a[2] = {(1,2),3}; // OK
f(a, (t=3, t+2), c); // OK, primero almacena 3 en t, luego llama a f con tres argumentos

El operador coma de nivel superior también está prohibido en los límites de array

// int a[2,3]; // error
int a[(2,3)]; // OK, VLA array de tamaño 3 (VLA porque (2,3) no es una expresión constante)

El operador coma no está permitido en expresiones constantes , independientemente de si está en el nivel superior o no

// static int n = (1,2); // Error: la expresión constante no puede llamar al operador coma

Operador de conversión

Ver cast operator

Operador condicional

La expresión del operador condicional tiene la forma

condición ? expresión-verdadera : expresión-falsa

donde

condition - una expresión de tipo escalar
expression-true - la expresión que será evaluada si condition se compara como diferente de cero
expression-false - la expresión que será evaluada si condition se compara como igual a cero

Solo las siguientes expresiones están permitidas como expression-true y expression-false

(desde C23)
  • una expresión es un puntero y la otra es la constante de puntero nulo (como NULL ) o un valor de tipo nullptr_t (desde C23)
  • una expresión es un puntero a objeto y la otra es un puntero a void (posiblemente calificado)
1) Primero, evalúa condition . Hay un sequence point después de esta evaluación.
2) Si el resultado de condition se compara como desigual a cero, ejecuta expression-true , de lo contrario ejecuta expression-false
3) Realiza una conversión desde el resultado de la evaluación al tipo común , definido de la siguiente manera:
1) si las expresiones tienen tipo aritmético, el tipo común es el tipo después de las usual arithmetic conversions
2) si las expresiones tienen tipo struct/union, el tipo común es ese tipo struct/union
3) si ambas expresiones son void, toda la expresión del operador condicional es una expresión void
4) si uno es un puntero y el otro es una constante de puntero nulo o un valor nullptr_t (desde C23) , el tipo es el tipo de ese puntero
5) si ambos son punteros, el resultado es el puntero al tipo que combina los calificadores cvr de ambos tipos apuntados (es decir, si uno es const int * y el otro es volatile int * , el resultado es const volatile int * ), y si los tipos eran diferentes, el tipo apuntado es el tipo compuesto .
6) si uno es un puntero a void, el resultado es un puntero a void con calificadores cvr combinados
7) si ambos tienen tipo nullptr_t , el tipo común también es nullptr_t
(desde C23)
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))
// si x es una Expresión Constante Entera entonces la macro se expande a
sizeof(*(1 ? NULL : (int *) 1))  // (void *)((x)*0l)) -> NULL
// de acuerdo con el punto (4) esto se convierte adicionalmente en
sizeof(int)
// si x no es una Expresión Constante Entera entonces la macro se expande a
// de acuerdo con el punto (6)
(sizeof(*(void *)(x))           // Error debido a tipo incompleto

Notas

El operador condicional nunca es una expresión lvalue , aunque puede retornar objetos de tipo struct/union. Las únicas otras expresiones que pueden retornar structs son assignment , comma , function call , y compound literal .

Tenga en cuenta que en C++, puede ser una expresión lvalue.

Consulte precedencia de operadores para los detalles sobre la precedencia relativa de este operador y la asignación.

El operador condicional tiene asociatividad de derecha a izquierda, lo que permite encadenamiento

#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 operador

Ver operador sizeof

_Alignof operador

Ver _Alignof operator

typeof operadores

Ver operadores typeof

Referencias

  • Estándar C23 (ISO/IEC 9899:2024):
  • 6.5.2.2 Llamadas a función (p: TBD)
  • 6.5.3.4 Operadores sizeof y _Alignof (p: TBD)
  • 6.5.4 Operadores de conversión (p: TBD)
  • 6.5.15 Operador condicional (p: TBD)
  • 6.5.17 Operador coma (p: TBD)
  • 6.7.3.5 Especificadores typeof (p: 115-118)
  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.5.2.2 Llamadas a función (p: 58-59)
  • 6.5.3.4 Operadores sizeof y _Alignof (p: 64-65)
  • 6.5.4 Operadores de conversión (p: 65-66)
  • 6.5.15 Operador condicional (p: 71-72)
  • 6.5.17 Operador coma (p: 75)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.5.2.2 Llamadas a función (p: 81-82)
  • 6.5.3.4 Los operadores sizeof y _Alignof (p: 90-91)
  • 6.5.4 Operadores de conversión (p: 91)
  • 6.5.15 Operador condicional (p: 100)
  • 6.5.17 Operador coma (p: 105)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.5.2.2 Llamadas a función (p: 71-72)
  • 6.5.3.4 El operador sizeof (p: 80-81)
  • 6.5.4 Operadores de conversión (p: 81)
  • 6.5.15 Operador condicional (p: 90-91)
  • 6.5.17 Operador coma (p: 94)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 3.3.2.2 Llamadas a funciones
  • 3.3.3.4 El operador sizeof
  • 3.3.4 Operadores de conversión
  • 3.3.15 Operador condicional
  • 3.3.17 Operador coma

Véase también

Operadores comunes
asignación incremento
decremento
aritméticos lógicos comparación acceso a
miembros
otros

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
(desde C11)
(hasta C23)

alignof
(desde C23)

Documentación de C++ para Otros operadores