¿Es posible, utilizando el preprocesador C / C ++, contar líneas dentro de un archivo fuente, ya sea en una macro o en algún tipo de valor disponible en tiempo de compilación? Por ejemplo, ¿puedo reemplazar MAGIC1, MAGIC2y MAGIC3en lo siguiente, y obtener el valor 4 de alguna manera cuando lo uso MAGIC3?
MAGIC1 // can be placed wherever you like before the relevant
// lines - either right before them, or in global scope etc.
foo(); MAGIC2
bar(); MAGIC2
baz(); MAGIC2
quux(); MAGIC2
// ... possibly a bunch of code here; not guaranteed to be in same scope ...
MAGIC3
Notas:
- Las extensiones específicas del compilador a las capacidades del preprocesador son aceptables pero indeseables.
- Si esto es posible solo con la ayuda de algunos de C ++, a diferencia de C, construir, eso también es aceptable pero indeseable (es decir, me gustaría algo que funcione para C).
- Obviamente, esto se puede hacer ejecutando el archivo fuente a través de un script de procesador externo, pero eso no es lo que estoy preguntando.
c++
c-preprocessor
einpoklum
fuente
fuente

__LINE__que representa el número de línea actual__COUNTER__y / oBOOST_PP_COUNTER?int arr[MAGIC4]y obtener el número de líneas en alguna sección previamente contada de mi código.Respuestas:
Existe la
__LINE__macro de preprocesador que le da un número entero para que aparezca la línea. Puede tomar su valor en alguna línea, y luego en una línea posterior, y comparar.Si desea contar las ocurrencias de algo en lugar de las líneas de origen,
__COUNTER__podría ser una opción no estándar, compatible con algunos compiladores como GCC y MSVC.Tomé el valor inicial de
__COUNTER__porque podría haber sido utilizado previamente en el archivo de origen, o algún encabezado incluido.En C en lugar de C ++, existen limitaciones en las variables constantes, por lo
enumque se podría usar una en su lugar.Reemplazando el const con
enum:fuente
__COUNTER__no es estándar en C o C ++. Si sabe que funciona con compiladores particulares, especifíquelos.BEFOREyAFTERno son macrosSé que la solicitud del OP es utilizar macros, pero me gustaría agregar otra forma de hacerlo que no implique el uso de macros.
C ++ 20 presenta la
source_locationclase que representa cierta información sobre el código fuente, como nombres de archivos, números de línea y nombres de funciones. Podemos usar eso con bastante facilidad en este caso.Y vivir ejemplo aquí .
fuente
source_locationser experimental en C ++ 20?source_locationahora es oficialmente parte de C ++ 20. Mira aquí . Simplemente no pude encontrar la versión del compilador gcc en godbolt.org que ya lo admite en sentido no experimental. ¿Puede explicar un poco más su afirmación: solo puedo usar el recuento de líneas en el mismo alcance que las líneas que he contado ?line_number_startyline_number_enddentro de ese alcance, en ningún otro lugar. Si lo quiero en otro lugar, necesito pasarlo en tiempo de ejecución, lo que frustra el propósito.line_number_endvisible en tiempo de compilación fuera de su alcance. Corrígeme si estoy equivocado.Para completar: si está dispuesto a agregar
MAGIC2después de cada línea, puede usar__COUNTER__:https://godbolt.org/z/i8fDLx (devoluciones
3)Puede hacerlo reutilizable almacenando los valores inicial y final de
__COUNTER__.En general, esto es realmente engorroso. Tampoco podrá contar líneas que contengan directivas de preprocesador o que terminen con
//comentarios. En su__LINE__lugar, usaría , ver la otra respuesta.fuente
static_assert?__COUNTER__que todavía es cero inicialmente, ya que otros encabezados, etc. podrían usarlo.__COUNTER__dos veces y tomar la diferencia__COUNTER__por sí solo no se permitiría, y debe expandirse a algo o no contará (no puedo recordar las reglas al 100% en esto).Una solución algo más robusta, que permite diferentes contadores (siempre que no se entremezclen y no sirvan
__COUNTER__para otras tareas):Esto oculta los detalles de implementación (aunque los oculta dentro de las macros ...). Es una generalización de la respuesta de @ MaxLanghof. Tenga en cuenta que
__COUNTER__puede tener un valor distinto de cero cuando comenzamos un conteo.Así es como se usa:
Además, esto es válido C, si su preprocesador es compatible
__COUNTER__, eso es.Funciona en GodBolt .
Si está utilizando C ++, puede modificar esta solución para ni siquiera contaminar el espacio de nombres global, colocando los contadores dentro
namespace macro_based_line_counts { ... }, onamespace detailetc.)fuente
Según su comentario, si desea especificar un tamaño de matriz (tiempo de compilación) en C o C ++, puede hacer
Si necesita
sizeof(array)en las líneas intermedias, puede reemplazarlo con una referencia de variable estática (a menos que sea absolutamente necesario que sea una expresión constante entera) y un compilador optimizador debe tratarlo de la misma manera (eliminar la necesidad de colocar la variable estática) en memoria)Una
__COUNTER__solución basada en (si esa extensión está disponible) en lugar de una__LINE__basada en la base funcionará igual.constexprs en C ++ debería funcionar tan bien comoenum, peroenumtambién funcionará en C simple (mi solución anterior es una solución de C simple).fuente
__COUNTER__solución basada también tiene problemas: es mejor que espere que su macro mágica sea el único usuario__COUNTER__, al menos antes de que termine de usar__COUNTER__. Básicamente, el problema se reduce a los hechos simples que__COUNTER__/__LINE__son características del preprocesador y el preprocesador funciona en una sola pasada, por lo que no puede realizar un backpatch de una expresión constante entera más tarde basada en__COUNTER__/__LINE__. La única forma (al menos en C) es evitar la necesidad en primer lugar, por ejemplo, mediante el uso de declaraciones de matriz directas sin tamaño (declaraciones de matriz con tipo incompleto).\no afecta__LINE__: si hay un salto de línea,__LINE__aumenta. Ejemplo 1 , ejemplo 2 .