Pregunta

Considere este código;

#define A 5
#define B 3

int difference = A - B;

¿El valor de "diferencia" está codificado como "2" en tiempo de compilación o se calcula en tiempo de ejecución?

¿Fue útil?

Solución

El A y B Las macros son un poco una distracción.Este:

#define A 5
#define B 3

int difference = A - B;

es exactamente equivalente a esto:

int difference = 5 - 3;

así que hablemos de esto último.

5 - 3 es un expresión constante, que es una expresión que "puede evaluarse durante la traducción en lugar del tiempo de ejecución y, en consecuencia, puede usarse en cualquier lugar donde pueda haber una constante".También es una *expresión constante entera".Por ejemplo, una etiqueta de caso debe ser una expresión constante entera, por lo que podría escribir esto:

switch (foo) {
    case 2: /* this is a constant */
    ...
}

o esto:

switch (foo) {
    case 5 - 3: /* this is a constant expression */
    ...
}

Pero tenga en cuenta que la definición dice que puede ser evaluado durante la traducción, no es que deba serlo.Hay algunos contextos que requieren expresiones constantes, y en esos contextos la expresión debe ser evaluado en tiempo de compilación.

Pero suponiendo que difference se declara dentro de alguna función, el inicializador no es uno de esos contextos.

Cualquier compilador que valga lo que pagas por él (incluso si es gratuito) reducirá 5 - 3 a 2 en tiempo de compilación y generar código que almacene el valor 2 en difference.Pero no es obligatorio hacerlo.El estándar C especifica la comportamiento de programas;no especifica cómo se debe implementar ese comportamiento.Pero es seguro asumir que cualquier compilador que estés usando reemplazará 5 - 3 por 2.

Incluso si escribes:

int difference = 2;

un compilador podría generar legalmente código que cargue el valor 5 en un registro, resta 3 de él y almacena el contenido del registro en difference.Sería una tontería hacerlo, pero el estándar del lenguaje no lo excluye.

Mientras el resultado final sea ese difference tiene el valor 2, al estándar del lenguaje no le importa cómo se hace.

Por otro lado, si escribes:

switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}

entonces el compilador debe calcule el resultado para que pueda diagnosticar el error (no puede tener dos etiquetas de caso con el mismo valor).

Finalmente, si define difference en el alcance del archivo (fuera de cualquier función), luego el valor inicial hace tiene que ser constante.Pero la verdadera distinción en ese caso no es si 5 - 3 será evaluado en el momento de la compilación, es si estás permitido utilizar una expresión no constante.

Referencia:El último borrador de la norma C 2011 es N1570 (PDF grande);Las expresiones constantes se analizan en la sección 6.6.

Otros consejos

La norma no especifica este tipo de cosas.No dice nada sobre posibles optimizaciones como esta (y por una buena razón).Un estándar define la semántica, no la implementación).

¿Por qué no mirar el desmontaje de su compilador?Eso te dará una respuesta definitiva.

...

Así que hagamos eso.

Aquí está el resultado de VC++ 10:

#include <iostream>

#define A 5
#define B 3

int main() {
    int x = A - B;
    std::cout << x;  // make sure the compiler doesn't toss it away
010A1000  mov         ecx,dword ptr [__imp_std::cout (10A2048h)]  
010A1006  push        2  
010A1008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]  
    return 0;
010A100E  xor         eax,eax  

Como puede ver, simplemente reemplazó la aparición de x con un valor estático de 2 y lo empujó a la pila para la llamada a cout.No evaluó la expresión en tiempo de ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top