2010-08-07 7 views
7

que por desgracia estaba haciendo un poco de arqueología código de hoy (mientras refactorización a cabo algunos de los antiguos códigos peligrosos) y encontró un pequeño fósil de esta manera:#line - propósitos de?

# line 7 "foo.y" 

yo estaba completamente atónito de encontrar un tesoro tan arcaica allí. Lo leí en un sitio web para la programación C. Sin embargo, no explicó por qué alguien querría usarlo. Me quedé solo, por lo tanto, para suponer que el programador lo puso simplemente por la pura alegría de mentirle al compilador.

Nota: (mente que el fósil era en realidad en la línea 3 del archivo CPP) (Ah, y el archivo se ha hecho apunta a un archivo .y que era casi idéntica a este archivo

¿Hay alguien. ¿Tiene alguna idea de por qué tal directiva sería necesaria? O ¿para qué se podría usar?

+0

+1 para prosaics :) – cHao

Respuesta

17

Generalmente se utiliza mediante herramientas automáticas de generación de código (como yacc o bison) para establecer el número de línea al valor de la línea en el archivo de origen real en lugar del archivo fuente C.

esta manera, cuando se produce un error que dice:

a += xyz; 
    ^No such identifier 'xyz' on line 15 of foo.y 

se puede ver en la línea 15 del fichero fuente real de ver el problema.

De lo contrario, dice algo ridículo como No such identifier 'xyz' on line 1723 of foo.c y tiene que correlacionar manualmente esa línea en su archivo C generado automáticamente con el equivalente en su archivo real. Confíe en mí, a menos que desee involucrarse profundamente en el análisis léxico y semántico (o si desea una hemorragia cerebral), no desea pasar por el código generado por yacc (bison puede generar un código mejor, no lo hago). Lo sé, pero no me importa realmente ya que escribo el código de nivel superior.

Tiene dos formas según la norma C99:

#line 12345 
#line 12345 "foo.y" 

Los primeros conjuntos sólo el número de línea se informó, el segundo cambia el nombre del archivo informado también, para que pueda obtener un error en la línea 27 del foo.y en lugar de foo.c.


En cuanto a "el programador lo puso simplemente por la pura alegría de mentirle al compilador", no. Puede que estemos torcidos y retorcidos, pero normalmente no somos malvados :-) Esa línea fue puesta allí por yacc o bison para hacerte un favor.

+0

Gracias por la respuesta. Eso ayuda ¿Estás diciendo que el archivo de código (en mi caso, un archivo .cpp) se autogenera? (Tenga en cuenta que no tengo experiencia en yacc). Debo añadir que hice diff los archivos y que eran prácticamente idénticos, excepto por algunos comentarios aquí y allá. –

+1

Casi seguro. Hay un programa yacc (viene con las cadenas de herramientas de desarrollo de UNIX) que debería tomar su foo.y y convertirlo en foo.c. Esto probablemente ocurra cada vez que crees, aunque es posible que tu desarrollador lo haya hecho una vez y luego haya comenzado a usar el archivo generado como está. Eso sería muy inusual (y difícil de mantener) especialmente dado que el archivo foo.y aún está disponible. Yacc/Lex son generadores de analizadores para facilitar el manejo de mini-idiomas en su propio código. – paxdiablo

+0

excelente para saber ¡gracias! También me aseguraré de modificar el archivo .y (aunque con mucho cuidado). –

5

El único lugar donde he visto que esta funcionalidad es útil es para el código generado. Si está utilizando una herramienta que genera el archivo C desde el origen definido en otra forma, en un archivo separado (es decir, el archivo ".y"), usar #line puede ayudar al usuario a saber dónde está el problema "real", y donde deberían ir para corregirlo (el archivo .y donde ponen el código original).

+0

Gracias por la respuesta. –

2

El propósito de la directiva #line es usar herramientas, los generadores de códigos pueden usarlo para que los depuradores (por ejemplo) puedan mantener el contexto de las cosas en el código del usuario o mensajes de error pueden referir al usuario a la ubicación en su archivo fuente.

Nunca he visto esa directiva utilizada por un programador que la coloca manualmente, y no estoy seguro de lo útil que sería.

2

Tiene un propósito más profundo. El preprocesador C original era un programa separado del compilador. Después de haber combinado varios archivos .h en el archivo .c, la gente aún quería saber que el mensaje de error proviene de la línea 42 de stdio.h o de la línea 17 de main.c. Sin algún medio de comunicación, el compilador de otra manera no tendría manera de saber qué archivo de origen contenía originalmente la línea ofensiva de código.

También influye en las tablas que necesita cualquier depurador de nivel de fuente para traducir entre el código generado y el archivo fuente y el número de línea.

Por supuesto, en este caso, está buscando un archivo que fue escrito por una herramienta (probablemente llamada yacc o bison) que se usa para crear analizadores a partir de una descripción de su gramática. Este archivo no es realmente un archivo fuente. Fue creado a partir del texto fuente real.

Si su arqueología lo está llevando a un problema con el analizador, querrá identificar qué generador de analizadores se está utilizando en realidad, y leer un poco sobre analizadores en general para que entienda por qué lo hace de esta manera en absoluto. La documentación para yacc, bison o cualquiera que sea la herramienta también será útil.

+0

Muy interesante sobre las aplicaciones separadas para el preprocesador y el compilador. Y, por cierto, el archivo tenía muchas de estas directivas allí. Pueden quedarse donde están. Prefiero cambiar otro código sin relación alguna cuando me encontré con estos. Así que con suerte no tendré que regenerar nada. –

+0

Los perseguidores son bestias delicadas. No quiere preocuparse por su digestión si no es necesario, especialmente si el análisis no es algo con lo que esté familiarizado. En un archivo típico generado por yacc, habrá al menos una directiva #line para cada bloque que implemente una producción de gramática. Eso será un montón de líneas para incluso una gramática de tamaño moderado. – RBerteig

1

He utilizado #line y #error para crear un archivo * .c temporal que usted compila y deja que su IDE le proporcione una lista de errores detectables encontrados por alguna herramienta de terceros.

Por ejemplo, conecté el archivo de salida de PC-LINT a una secuencia de comandos perl que convirtió los errores legibles para las líneas #line y #error. Luego compilé esta salida y mi IDE me permite pasar por cada error usando F4. Mucho más rápido que abriendo manualmente cada archivo y saltando a una línea en particular.