É possível, usando o pré-processador C / C ++, contar linhas dentro de um arquivo de origem, em uma macro ou em algum tipo de valor disponível no tempo de compilação? Por exemplo, eu pode substituir MAGIC1
, MAGIC2
e MAGIC3
no seguinte, e obter o valor 4 de alguma forma quando se utiliza 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:
- Extensões específicas do compilador para os recursos do pré-processador são aceitáveis, mas indesejáveis.
- Se isso for possível apenas com a ajuda de algumas das construções em C ++, em oposição a C, isso também é aceitável, mas indesejável (ou seja, eu gostaria de algo que funcionasse para C).
- Obviamente, isso pode ser feito executando o arquivo de origem através de algum script de processador externo, mas não é isso que estou perguntando.
c++
c-preprocessor
einpoklum
fonte
fonte
__LINE__
que representa o número da linha atual__COUNTER__
e / ouBOOST_PP_COUNTER
?int arr[MAGIC4]
e obter o número de linhas em alguma seção contada anteriormente do meu código.Respostas:
Existe a
__LINE__
macro do pré - processador que fornece um número inteiro para a linha em que é exibida. Você pode pegar seu valor em alguma linha, e depois em outra linha, e comparar.Se você deseja contar as ocorrências de algo em vez de linhas de origem,
__COUNTER__
pode ser uma opção não padrão, suportada por alguns compiladores, como GCC e MSVC.Peguei o valor inicial de
__COUNTER__
porque ele poderia ter sido usado anteriormente no arquivo de origem ou em algum cabeçalho incluído.Em C, e não em C ++, há limitações em variáveis constantes; portanto, um
enum
pode ser usado.Substituindo a const por
enum
:fonte
__COUNTER__
não é padrão em C ou C ++. Se você sabe que funciona com determinados compiladores, especifique-os.BEFORE
eAFTER
não são macrosSei que a solicitação do OP é usar macros, mas gostaria de adicionar outra maneira de fazer isso que não envolve o uso de macros.
O C ++ 20 apresenta a
source_location
classe que representa certas informações sobre o código-fonte, como nomes de arquivos, números de linhas e nomes de funções. Podemos usar isso com bastante facilidade neste caso.E exemplo ao vivo aqui .
fonte
source_location
ser experimental em C ++ 20?source_location
agora faz parte oficialmente do C ++ 20. Confira aqui . Eu simplesmente não consegui encontrar a versão do compilador gcc no godbolt.org que já a suporta no sentido não experimental. Você pode explicar um pouco mais a sua declaração - só posso usar a contagem de linhas no mesmo escopo que as linhas que contei ?line_number_start
eline_number_end
dentro desse escopo, em nenhum outro lugar. Se eu quiser em outro lugar, preciso passá-lo em tempo de execução - o que anula o objetivo.line_number_end
visível em tempo de compilação fora do seu escopo. Corrija-me se eu estiver errado.Para completar: se você deseja adicionar
MAGIC2
depois de cada linha, pode usar__COUNTER__
:https://godbolt.org/z/i8fDLx (retorna
3
)Você pode torná-lo reutilizável armazenando os valores inicial e final de
__COUNTER__
.No geral, isso é realmente complicado. Você também não poderá contar linhas que contêm diretivas de pré-processador ou que terminam com
//
comentários. Eu usaria em__LINE__
vez disso, veja a outra resposta.fonte
static_assert
?__COUNTER__
ainda é zero inicialmente, pois outros cabeçalhos etc. podem usá-lo.__COUNTER__
duas vezes e fazer a diferença__COUNTER__
- conhecidoas_463035818 por si só não seria permitido, e ele precisa ser expandido para algo ou não será contado (não lembro as regras 100% sobre isso).Uma solução um pouco mais robusta, que permite contadores diferentes (desde que não se misturem e que não sejam utilizados
__COUNTER__
para outras tarefas):Isso oculta os detalhes da implementação (embora oculte-os dentro de macros ...). É uma generalização da resposta de @ MaxLanghof. Observe que
__COUNTER__
pode ter um valor diferente de zero quando iniciamos uma contagem.Veja como é usado:
Além disso, isso é C válido - se o seu pré-processador suportar
__COUNTER__
, é isso.Funciona no GodBolt .
Se você estiver usando C ++, poderá modificar esta solução para não poluir o namespace global - colocando os contadores dentro
namespace macro_based_line_counts { ... }
ounamespace detail
etc.)fonte
Com base no seu comentário, se você quiser especificar um tamanho de matriz (em tempo de compilação) em C ou C ++, poderá fazer
Se você precisar
sizeof(array)
nas linhas intermediárias, poderá substituí-lo por uma referência de variável estática (a menos que seja absolutamente necessária uma expressão constante inteira) e um compilador de otimização deve tratá-la da mesma forma (eliminar a necessidade da variável estática ser colocada em memória)Uma
__COUNTER__
solução baseada em A (se essa extensão estiver disponível) em oposição a uma solução baseada em A__LINE__
funcionará da mesma maneira.constexpr
s em C ++ deve funcionar tão bem quantoenum
, masenum
também funcionará em C simples (minha solução acima é uma solução C simples).fonte
__COUNTER__
solução baseada também tem problemas: é melhor você esperar que sua macro mágica seja o único usuário__COUNTER__
, pelo menos antes de terminar de usar__COUNTER__
. O problema basicamente se resume aos fatos simples que__COUNTER__/__LINE__
são os recursos do pré-processador e o pré-processador funciona de uma só vez; portanto, você não pode retroceder uma expressão constante inteira posteriormente com base em__COUNTER__
/__LINE__
. A única maneira (pelo menos em C) é evitar a necessidade em primeiro lugar, por exemplo, usando declarações de matriz direta sem tamanho (declarações de matriz com tipo incompleto).\
não afeta__LINE__
- se houver uma quebra de linha,__LINE__
aumenta. Exemplo 1 , exemplo 2 .