4.10.5 Sentencias de expresiones con coma
§1 Sinopsis
En ocasiones las sentencias contienen expresiones con coma, que describimos a continuación; convirtiéndose así en bloques de código, ya que cada subexpresión de la expresión con coma se ejecuta como una entidad separada.
§2 Expresiones con coma
Las expresiones con coma son conjuntos de subexpresiones separadas por coma, que aquí es un operador
( 4.9.5), y agrupadas por paréntesis.
Cada subexpresión se evalúa una a continuación de otra empezando por la izquierda,
el resultado es el valor de la última.
Ejemplos
sum = (i = 3, i++, i++); // sum = 4, i = 5
func(i, (j = 1, j + 4), k); // llama func con 3 argumentos (i,5,k) no 4
func(i, j); // llama func con
dos argumentos
func((exp1, exp2), (exp3, exp4, exp5)); // ídem con dos argumentos
Los siguientes pares de expresiones son equivalentes:
(a, b) += 12;
(a, b += 12);
&(a, b);
(a, &b);
Nota: no deben confundirse la expresiones con coma, de las que separan los parámetros de las
funciones (donde la coma se usa como puntuador
3.2.6). Aunque es legal mezclar ambos usos, para evitar ambigüedades, es necesario emplear
paréntesis, como en los ejemplos anteriores.
§3 Comentario
Como una pincelada de los usos que pueden darse a estas expresiones, a continuación mostramos un ejemplo tomado de un caso real, encontrado en un programa Windows de un reconocido autor. En el fuente leemos las siguientes sentencias (sin ninguna explicación adicional):
case WM_DESTROY: // Window is being destroyed
return HANDLE_WM_DESTROY (hwnd, wParam, lParam, mainFrame_OnDestroy);
aquí los valores hwnd, wParam y lParam están perfectamente identificados (son frecuentísimos en los programas que utiliza la API de Windows), pero la expresión en sí misma resulta un tanto extraña, ya que aparenta ser la invocación de una función cuyo nombre es inusual (parece una constante), y en principio HANDLE_WM_DESTROY no aparece en ninguna otra parte del fuente ni en la documentación de la API de Windows. Por su parte, mainFrame_OnDestroy es una función cuya definición en el mismo fuente, tiene el siguiente aspecto:
static void mainFrame_OnDestroy (HWND hwnd) {
/* ... */
}
Una búsqueda más concienzuda nos muestra que HANDLE_WM_DESTROY es un define situado en el fichero de cabecera windowsx.h:
#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)
En consecuencia, una vez que el pre-procesador ha realizado las sustituciones oportunas, las sentencias originales se traducen en:
case WM_DESTROY: // Window is being destroyed
return (mainFrame_OnDestroy(hwnd), 0L);
La segunda línea es una expresión con coma, cuya primera subexpresión es una invocación a mainFrame_OnDestroy, y la segunda es un long de valor cero (0L), que es el resultado (el valor realmente devuelto). Así pues, las sentencias originales equivalen a lo siguiente:
case WM_DESTROY: // Window is being destroyed
mainFrame_OnDestroy (hwnd);
return 0L;