c - studio - etiqueta de titulo en html
¿Qué hace el operador de coma, hacer? (8)
¿Qué hace el operador, en C?
Causa la evaluación de declaraciones múltiples, pero usa solo la última como valor resultante (valor de r, creo).
Asi que...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
debería dar como resultado que x se establezca en 8.
Como las respuestas anteriores han declarado que evalúa todas las declaraciones, pero utiliza la última como el valor de la expresión. Personalmente, solo lo encontré útil en expresiones de bucle:
for (tmp=0, i = MAX; i > 0; i--)
El único lugar donde lo he visto útil es cuando escribes un bucle funky donde quieres hacer varias cosas en una de las expresiones (probablemente la expresión de inicio o la expresión de bucle. Algo como:
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
Perdónenme si hay algún error de sintaxis o si mezclo algo que no sea estricto. C. No estoy argumentando que el operador es de buena forma, pero para eso podría usarlo. En el caso anterior, probablemente usaría un ciclo while para que las expresiones múltiples en init y loop sean más obvias. (Y yo inicializaría i1 e i2 en línea en lugar de declarar y luego inicializar ... bla, bla, bla.)
El operador de coma evaluará el operando de la izquierda, descartará el resultado y luego evaluará el operando de la derecha y ese será el resultado. El uso idiomático como se indica en el enlace es cuando se inicializan las variables utilizadas en un ciclo for
, y da el siguiente ejemplo:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
De lo contrario, no hay muchos usos excelentes del operador de coma , aunque es fácil abusar de él para generar código que es difícil de leer y mantener.
Del borrador del estándar C99, la gramática es la siguiente:
expression:
assignment-expression
expression , assignment-expression
y el párrafo 2 dice:
El operando izquierdo de un operador de coma se evalúa como una expresión vacía; hay un punto de secuencia después de su evaluación. Entonces se evalúa el operando correcto; el resultado tiene su tipo y valor. 97) Si se intenta modificar el resultado de un operador de coma o acceder a él después del siguiente punto de secuencia, el comportamiento no está definido.
La nota al pie 97 dice:
Un operador de coma no produce un valor l .
lo que significa que no puede asignar el resultado del operador de coma .
Es importante tener en cuenta que el operador de coma tiene la precedencia más baja y, por lo tanto, hay casos en los que using ()
puede marcar una gran diferencia, por ejemplo:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d/n", x, y ) ;
}
tendrá el siguiente resultado:
1 4
El operador de coma combina las dos expresiones a cada lado en una, evaluándolas en orden de izquierda a derecha. El valor del lado derecho se devuelve como el valor de la expresión completa. (expr1, expr2)
es como { expr1; expr2; }
{ expr1; expr2; }
{ expr1; expr2; }
pero puede usar el resultado de expr2
en una llamada o asignación de función.
A menudo se ve en los bucles for
inicializar o mantener múltiples variables como esta:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
Aparte de esto, solo lo he usado "enojado" en otro caso, al finalizar dos operaciones que siempre deberían ir juntas en una macro. Teníamos código que copiaba varios valores binarios en un búfer de bytes para enviar en una red, y un puntero mantenido donde habíamos llegado a:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Donde los valores fueron short
s o int
s hicimos esto:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Más tarde leemos que esto no era realmente válido C, porque (short *)ptr
ya no es un valor l y no puede incrementarse, aunque a nuestro compilador en ese momento no le importó. Para solucionar esto, dividimos la expresión en dos:
*(short *)ptr = short_value;
ptr += sizeof(short);
Sin embargo, este enfoque se basó en que todos los desarrolladores recordaran poner ambas declaraciones en todo momento. Queríamos una función en la que pudiéramos pasar el puntero de salida, el valor y el tipo del valor. Siendo C, no C ++ con plantillas, no podríamos tener una función tomando un tipo arbitrario, por lo que decidimos en una macro:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Al usar el operador de coma, pudimos usar esto en expresiones o como enunciados como deseábamos:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
¡No estoy sugiriendo que ninguno de estos ejemplos sea un buen estilo! De hecho, parece recordar el Código Completo de Steve McConnell que aconseja no usar operadores de coma en un bucle for
: para la legibilidad y la mantenibilidad, el bucle debe controlarse con una sola variable, y las expresiones en la línea for
solo deben contener control de bucle código, no otros bits adicionales de inicialización o mantenimiento de bucle.
El operador de coma no tiene ningún significado, es una función 100% superflua. El uso principal es "personas que intentan ser inteligentes" y, por lo tanto, lo utilizan para (involuntariamente) ofuscar el código legible. El área principal de uso es ofuscar los bucles, por ejemplo:
for(int i=0, count=0; i<x; i++, count++)
Donde int i=0, count=0
realidad no es el operador de coma, sino una lista de declaraciones (ya estamos confundidos aquí). i++, count++
es el operador de coma, que evalúa primero el operando izquierdo y luego el operando derecho. El resultado del operador de coma es el resultado del operando correcto. El resultado del operando izquierdo se descarta.
Pero el código anterior podría escribirse de una manera mucho más legible sin el operador de coma:
int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
...
count++;
}
El único uso real del operador de coma que he visto, son las discusiones artificiales sobre los puntos de secuencia, ya que el operador de coma viene con un punto de secuencia entre la evaluación de los operandos izquierdo y derecho.
Entonces, si tienes un código de comportamiento indefinido como este:
printf("%d %d", i++, i++);
En realidad, puede convertirlo en un comportamiento meramente no especificado (orden de evaluación de los parámetros de la función) al escribir
printf("%d %d", (0,i++), (0,i++));
Ahora hay un punto de secuencia entre cada evaluación de i++
, por lo que al menos el programa no correrá el riesgo de colapsarse y arder, aunque el orden de evaluación de los parámetros de la función sigue sin especificarse.
Por supuesto, nadie escribiría dicho código en aplicaciones reales, solo es útil para las discusiones entre abogados sobre puntos de secuencia en el lenguaje C.
El operador de coma está prohibido por MISRA-C: 2004 y MISRA-C: 2012 con la justificación de que crea un código menos legible.
He visto más utilizado en los ciclos while:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
Hará la operación, luego realizará una prueba basada en un efecto secundario. La otra forma sería hacerlo así:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
La expresion:
(expression1, expression2)
Se evalúa la primera expresión1, luego se evalúa la expresión2 y se devuelve el valor de la expresión2 para toda la expresión.