¿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
, MAGIC2
y MAGIC3
en 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
enum
que 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.BEFORE
yAFTER
no 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_location
clase 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_location
ser experimental en C ++ 20?source_location
ahora 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_start
yline_number_end
dentro 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_end
visible en tiempo de compilación fuera de su alcance. Corrígeme si estoy equivocado.Para completar: si está dispuesto a agregar
MAGIC2
despué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 detail
etc.)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.constexpr
s en C ++ debería funcionar tan bien comoenum
, peroenum
tambié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 .