
Juez Maygarden
si escribo un #definir que realiza una operación utilizando otras constantes del preprocesador, ¿se calcula el valor final cada vez que aparece la macro en tiempo de ejecución? ¿Esto depende de las optimizaciones en el compilador o está cubierto por un estándar?
Ejemplo:
#define EXTERNAL_CLOCK_FREQUENCY 32768
#define TIMER_1_S EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS TIMERB_1_S / 10
¿Será la operación 32768 / 10 ocurre en tiempo de ejecución cada vez que uso la macro TIMER_100_MS?
Me gustaría evitar lo siguiente:
#define EXTERNAL_CLOCK_FREQUENCY 32768
#define TIMER_1_S EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS 3276
Resumen
Se requiere un compilador para poder evaluar expresiones integrales constantes porque son necesarias para calcular cosas como tamaños de matrices en tiempo de compilación. Sin embargo, el estándar solo dice que “pueden”, no “deben”, hacerlo. Por lo tanto, solo un compilador con cerebro muerto no evaluaría expresiones integrales constantes en tiempo de compilación, pero una simple verificación de la salida del ensamblado para un compilador no convencional verificaría cada caso.
Las macros son simplemente sustitución textual, por lo que en su ejemplo de escritura TIMER_100_MS
en un programa es una forma elegante de escribir 32768 / 10
.
Por lo tanto, la pregunta es cuándo evaluaría el compilador 32768 / 10
, que es una expresión integral constante. No creo que el estándar requiera ningún comportamiento particular aquí (ya que la evaluación en tiempo de ejecución y en tiempo de compilación es indistinguible en efecto), pero cualquier compilador medianamente decente lo evaluará en tiempo de compilación.

Johannes Schaub – litb
La mayoría de las respuestas aquí se centraron en el efecto de la macro sustitución. Pero creo que quería saber si
32768 / 10
se evalúa en tiempo de compilación. En primer lugar, esa es una expresión constante aritmética y, además, una expresión constante integral (porque solo tiene literales de tipo entero). La implementación es libre de calcularlo en tiempo de ejecución, pero también debe poder calcularlo en tiempo de compilación, porque
- debe dar un mensaje de diagnóstico si una expresión constante no es representable en el tipo que tiene su expresión
- tales expresiones están permitidas en contextos que requieren el valor en el momento de la traducción, por ejemplo, si se usan como el tamaño de una dimensión de matriz.
Si el compilador puede calcular principalmente el resultado ya en tiempo de compilación, debería usar ese valor y no volver a calcularlo en tiempo de ejecución, creo. Pero tal vez todavía hay alguna razón para hacer eso. no sabría
Editar: Lo siento, he respondido la pregunta como si fuera sobre C++. Noté que hoy preguntó sobre C. El desbordamiento en una expresión se considera un comportamiento indefinido en C, independientemente de si ocurre en una expresión constante o no. El segundo punto también es cierto en C, por supuesto.
Editar: Como señala un comentario, si la macro se sustituye por una expresión como 3 * TIMER_100_MS
entonces esto evaluaría (3 * 32768) / 10
. Por lo tanto, la respuesta simple y directa es “No, no ocurriría en tiempo de ejecución cada vez, porque la división puede no ocurrir en absoluto debido a las reglas de precedencia y asociatividad”. Mi respuesta anterior asume que la macro siempre se sustituye de modo que la división realmente ocurra.
No conozco ningún estándar que garantice que se optimizará. El preprocesador sustituirá 32768/10 por TIMER_100_MS, que puede ver ejecutando gcc -c. Para ver si el compilador se está optimizando aún más, ejecute gcc -S y verifique el ensamblador. Con gcc 4.1, incluso sin banderas de optimización, esto se reduce a la constante durante la compilación:
#include <stdlib.h>
#include <stdio.h>
#define EXTERNAL_CLOCK_FREQUENCY 32768
#define TIMER_1_S EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS TIMER_1_S / 10
int main(int argc, char **argv)
{
printf("%d\n", TIMER_100_MS);
return(0);
}
gcc -S test.c
cat test.s
...
popl %ebx
movl $3276, 4(%esp)
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_printf$stub
...
El compilador debería optimizar esa expresión. No creo que el estándar lo requiera, pero nunca he visto un compilador que NO realice esa tarea.
Sin embargo, NO debe escribir:
#define TIMER_100_MS TIMERB_1_S / 10
… porque eso es un error esperando a suceder. Siempre debe poner entre paréntesis #defines que involucran expresiones.
#define TIMER_100_MS (TIMERB_1_S / 10)
Considerar :
i = 10 * TIMER_100_MS;
El primer caso daría 32768 ((10*TIMERB_1_S)/10), el segundo 32760 (10*(TIMERB_1_S/10)). No es una diferencia crítica aquí, ¡pero DEBE ser consciente de ello!

Juez Maygarden
Desde el Borrador del Comité WG14/N1124 — 6 de mayo de 2005 ISO/IEC 9899:TC2:
6.6 Expresiones constantes
Sintaxis
expresión-constante:
expresión condicional
Descripción
Una expresión constante se puede evaluar durante la traducción en lugar del tiempo de ejecución y, en consecuencia, se puede usar en cualquier lugar donde se encuentre una constante.
Restricciones
Las expresiones constantes no deben contener operadores de asignación, incremento, decremento, llamada de función o coma, excepto cuando están contenidos dentro de una subexpresión que no se evalúa.96)
Cada expresión constante se evaluará como una constante que esté en el rango de valores representables para su tipo.

Bill el lagarto
¿Ocurrirá la operación 32768/10 en tiempo de ejecución cada vez que use el TIMERB_100_MS ¿macro?
Cada lugar en su código donde usa TIMERB_100_MS
será reemplazado por 32768 / 10
por el preprocesador.
Si esa expresión se optimiza aún más (se evalúa como una constante) depende de su compilador.

norman ramsey
Amigos, esta transformación se llama “plegamiento constante” e incluso la mayoría de los estudiantes compiladores lo hacen. Siempre que tenga un compilador creado por alguien que no sea usted o su compañero de cuarto de la universidad y esté compilando un lenguaje escrito estáticamente, puede contar con él incluso sin la optimización activada. Es un asunto diferente si se trata de un lenguaje dinámico extravagante que puede cambiar el significado de /
.
tenga en cuenta que
TIMERB_1_S / 10
es3276
no3277
–MM
4 de febrero de 2016 a las 0:08