2011-08-16 13 views
6

supuesta entrevista pregunta y respuesta here.¿Es esta explicación precisa para el código C que no se compilará?

¿Se compilará el siguiente código (en C)?

#define X 8; 
int main(void) 
{ 
    ++X; // will this line compile? 
}` 

No soy experto en C, pero sé que algunos C++ y pensamiento: por supuesto que no, no se puede incrementar el número 8, que es un valor de lado derecho. Por supuesto, el preprocesador reemplaza el X con el 8 antes de intentar compilar, y cuando intenta compilar, falla por ese mismo motivo. Por otra parte, yo soy el que la lectura de sitios web pregunta de la entrevista por lo que entonces pensé que sabe ...

Aquí está la explicación dada:

"Estrictamente hablando, el operando del prefijo (o postfix) operador de incremento debe ser un lvalue no modificable. Ahora que sabemos qué es un valor l, debemos preguntarnos si X es un valor l. X es una macro, lo que significa que no identifica un lugar en la memoria: las macros usan el reemplazo de texto simple a través del preprocesador. Debido a que las macros no existen en una región de la memoria, no son valores. Esto significa que X no se puede usar como un operando del operador de incremento de prefijo. Por lo tanto, el código que se muestra arriba no se compilará ".

¿Esta explicación es tan simple como creo que es?

¿Cuántos errores puedes encontrar arriba? Creo que tal vez esa debe ser la pregunta de la entrevista ...

y esto es apenas divertido:.

"Intuitivamente, es posible que pueda decir que el código anterior no compilará - sin saber exactamente por qué Sin embargo, en una situación de entrevista, se espera que brinde algún razonamiento como el que se da arriba. Las respuestas simples de sí o no simplemente no lo cortarán en una entrevista ".

+5

No, no compilará, ya que debería ser '#define X 8', sin'; ' –

+1

Suena muy ... académico ... :) – Torp

+1

Bien , también es un error (en C89, y según cualquier conjunto de advertencias cuerdo y pautas del programador) no 'devolver 0;' o algún otro número al final de 'main' ... –

Respuesta

5

¿Es esta explicación tan útil como creo?

Sí.

"Estrictamente hablando, el operando del prefijo (o postfix) operador de incremento debe ser un valor-I no modificable ...

Qué Un lvalue no modificable es algo así como const int n; - te puede tomar su dirección (a través de &), pero no se puede asignar a ella (a través de =, += o ++). no se puede incrementar algo que no es modificable.

para citar la norma (6.5.3.1 párrafo 1):

El operando del operador de incremento o decremento de prefijo debe tener calificada o tipo real o puntero no compensado y debe ser un valor modi fi cable.

Ahem.

X es una macro, lo que significa que no identifica un lugar en la memoria: las macros usan la sustitución de texto simple a través del preprocesador.

Esto es falso. Las macros no existen en el lenguaje C *. Forman parte del preprocesador, que no tiene ningún concepto de lvalues, rvalues, expressions o memory. Este particular macro se expande a una constante entera, que es un valor 0, pero las macros en sí no tienen nada que ver con ninguna de las anteriores. Ver Steve Jessop's answer para un contraejemplo de una macro que es un lvalue.

La respuesta correcta es que la declaración se expande a ++8, y desde 8 es un valor de lado derecho que no puede ser utilizado como un argumento a ++ (ya sea en forma), y por lo tanto no se compilará. Además, dependiendo de si desea que este código se compile como C89 o C99, dejar main sin un valor explícito return probablemente da un comportamiento indefinido.

* Si esta va a ser la respuesta aceptada, supongo que debería aclarar este bit: el preprocesador es como parte del lenguaje de programación C. Se especifica en el estándar C, y un compilador tiene que implementar el preprocesamiento para ser un compilador de C. Sin embargo, el "lenguaje" C (es decir, la sintaxis, la semántica, la biblioteca, etc.) no interactúa con el preprocesador: una vez que se llega a la etapa en la que se comienzan a trabajar con valores l y valores, el preprocesador hace mucho tiempo y todas las macros están completamente expandidas.Las macros ellos mismos no tienen ningún lugar en la sintaxis, ya que no son parte del "idioma". Hubo cierto debate (en la respuesta de Steve Jessop) acerca de si el uso del término "idioma" aquí es engañoso, y estoy de acuerdo con él en que es, simplemente no puedo encontrar una palabra mejor para usar en su lugar.

2

No se compilará por la misma razón exacta que (!):

8 = 8+1; 

no se compilará.

No se puede modificar (aquí incrementar) una constante.

10

La explicación dada es incorrecto:

X es una macro, lo que significa que no se identifica un lugar en la memoria - macros utilizan la sustitución de texto simple a través del preprocesador.

Precisamente porque las macros son de reemplazo simplemente texto, que pueden ampliar a un valor-i, o para el caso cualquier otra cosa. Por ejemplo:

int x; 
#define X x 

int main() { 
    ++X; 
} 

está bien. Es cierto que la macro no tiene un lugar en la memoria, pero eso es irrelevante si ++X; está bien formado, ya que ++X; no significa, "incrementar la macro X", significa "expandir la macro X y luego pegarse" ++ en el frente, ; en la parte posterior, y realizar análisis sintáctico y semántico en el resultado ".

Lo que dice la explicación acerca de "macros", debería decir acerca de constantes enteras. 8 no es un lvalue, y eso es lo que importa aquí.

Con este cambio, la explicación es OK [Editar - como Chris señala en un comentario, todavía no está bien, escribe "el operando del prefijo (o postfix) operador de incremento debe ser un no modificable lvalue ": debería decir" modificable "]

+1

Las macros +1 no son parte del lenguaje C en sí y no tienen ninguna relación con lvalues, rvalues, expressions y memory. Es solo la expansión de la macro lo que es relevante. (Aunque decir que el argumento de '++' debe ser un valor l no modificable también es falso.) –

+1

No estoy seguro de que sea útil decir que las macros no son parte del "lenguaje C mismo". No son opcionales, son parte del estándar. Pero si quiere cortar el estándar en "idioma" frente a "bibliotecas" frente a "preprocesador", de modo que, por ejemplo, 'sizeof' es" parte del lenguaje ", mientras que' INT_MIN' no es "parte del idioma", entonces ciertamente puede hacer una división limpia entre el preprocesador, el "compilador adecuado", los encabezados estándar, el enlazador y posiblemente algunos otros componentes, ya que las etapas de la traducción están claramente separadas en el estándar. –

+0

Y, heh, me perdí ese error tipográfico "no modificable". –

2

La explicación es correcta acerca de que el código no se compilará, pero está muy mal en todos los demás aspectos.

Se pierde por completo el hecho de que el compilador no verá X, se verá ++8;;, por lo que toda la perorata acerca de si un operador podría aplicar a X no tiene sentido. Sería mucho mejor responder simplemente "No" que dar esa explicación.

0

No compilará, ya que se requieren valores de ubicación para el operador de prefijo. 8 siendo una constante, falla. Puede leer más sobre el valor L aquí: L-Value and R-Value Expressions

Cuestiones relacionadas