Uso de __FILE__, __LINE__ e __FUNCTION__ em C ++

158

Presumindo que o seu compilador C ++ apoia-los, há alguma razão em particular não para uso __FILE__, __LINE__e __FUNCTION__para fins de depuração registro e?

Estou preocupado principalmente em fornecer ao usuário dados enganosos - por exemplo, relatar o número ou a função da linha incorreta como resultado da otimização - ou sofrer um impacto no desempenho como resultado.

Basicamente, eu posso confiar __FILE__, __LINE__e __FUNCTION__para sempre fazer a coisa certa?

Runcible
fonte
LINE deve fazer a coisa certa. Eu o usei e suas coortes extensivamente, incluindo PRETTY_FUNCTION . ... Mas ... bem, agora estou olhando o código onde LINE está. Provavelmente porque está em um bloco catch para manipulação de exceção try / catch.
Krazy Glew
4
: relevante referência gcc para macros predefinidos
Alexander Malakhov

Respostas:

191

__FUNCTION__não é padrão, __func__existe no C99 / C ++ 11. Os outros ( __LINE__e __FILE__) estão bem.

Ele sempre reportará o arquivo e a linha corretos (e funcionará se você optar por usar __FUNCTION__/ __func__). A otimização não é um fator, pois é uma expansão da macro de tempo de compilação; isso nunca afetará o desempenho de nenhuma maneira.

Evan Teran
fonte
3
__func__é meio que um problema em C ++. C99 não diz uma palavra sobre argumentos padrão e assim por diante, casos em que não é tão óbvio como __func__deve se comportar em C ++.
precisa saber é o seguinte
4
@thr: enquanto você faz um bom argumento. Eu estava bem claro que __func__existe em c99, não em c ++. Independentemente disso, acho que uma implementação razoável do __func__c ++ resultaria apenas no nome mutilado. Como não sou escritor de compiladores, essa não é minha decisão.
precisa saber é o seguinte
Quais compiladores não suportam __FUNCTION__? Quais compiladores, exceto o recente gcc, tratam isso como uma variável, não como uma macro?
bacia
36
__func__agora está no padrão C ++ 11.
VX
38

Em casos raros, pode ser útil alterar a linha fornecida por __LINE__outra coisa. Eu já vi o GNU configurar fazer isso para que alguns testes relatem números de linhas apropriados após a inserção de um vodu entre linhas que não aparecem nos arquivos originais. Por exemplo:

#line 100

Inicia as linhas a seguir com __LINE__100. Como opção, você pode adicionar um novo nome de arquivo

#line 100 "file.c"

Isso raramente é útil. Mas se for necessário, não há alternativas que conheço. Na verdade, em vez da linha, uma macro também pode ser usada, o que deve resultar em qualquer uma das duas formas acima. Usando a biblioteca de pré-processador boost, você pode incrementar a linha atual em 50:

#line BOOST_PP_ADD(__LINE__, 50)

Eu pensei que era útil mencioná-lo, uma vez que você perguntou sobre o uso de __LINE__e __FILE__. Nunca se obtém surpresas suficientes em C ++ :)

Edit: @ Jonathan Leffler fornece mais alguns casos de uso bons nos comentários:

Brincar com #line é muito útil para pré-processadores que desejam manter os erros relatados no código C do usuário alinhados com o arquivo de origem do usuário. Yacc, Lex e (mais em casa para mim) os pré-processadores ESQL / C fazem isso.

Johannes Schaub - litb
fonte
29

FYI: g ++ oferece a macro __PRETTY_FUNCTION__ não padrão. Até agora eu não sabia sobre o C99 __func__ (obrigado Evan!). Acho que ainda prefiro __PRETTY_FUNCTION__ quando estiver disponível para o escopo de classe extra.

PS:

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}
Mr.Ree
fonte
2
É bom saber sobre o __PRETTY_FUNCTION__. Muito útil!
Zheng Qu
8

Pessoalmente, estou relutante em usá-los para qualquer coisa, exceto mensagens de depuração. Eu fiz isso, mas tento não mostrar esse tipo de informação aos clientes ou usuários finais. Meus clientes não são engenheiros e, às vezes, não são conhecedores de computadores. Posso registrar essas informações no console, mas, como disse, com relutância, exceto pelas compilações de depuração ou por ferramentas internas. Suponho que isso dependa da base de clientes que você possui.

Craig S
fonte
29
"Eu poderia registrar essas informações para o console" - ou melhor ainda: log-lo para um arquivo para que se algo der errado, você pode pedir ao cliente para enviá-lo para você ...
Christoph
7

C ++ 20 std::source_location

O C ++ finalmente adicionou uma opção não macro e provavelmente dominará em algum momento no futuro quando o C ++ 20 se espalhar:

A documentação diz:

constexpr const char * nome_da_função () const noexcept;

6 Retorna: se este objeto representa uma posição no corpo de uma função, retorna um NTBS definido pela implementação que deve corresponder ao nome da função. Caso contrário, retorna uma string vazia.

onde NTBS significa "Cadeia de bytes nulos terminados".

Vou tentar quando o suporte chegar ao GCC, o GCC 9.1.0 com g++-9 -std=c++2aainda não o suporta.

https://en.cppreference.com/w/cpp/utility/source_location afirma que o uso será como:

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int main() {
    log("Hello world!");
}

Saída possível:

info:main.cpp:16:main Hello world!

__PRETTY_FUNCTION__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Respondida em: Qual é a diferença entre __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Ciro Santilli adicionou uma nova foto
fonte
1
Existe <experimental/source_location>no atual gcc-9.
陈浩南
5

Eu os uso o tempo todo. A única coisa com que me preocupo é ceder o IP nos arquivos de log. Se os nomes das suas funções forem realmente bons, você poderá facilitar a descoberta de um segredo comercial. É como enviar com símbolos de depuração, mas é mais difícil encontrar coisas. Em 99,999% dos casos, nada de ruim resultará disso.

JeffCharter
fonte
1
Bom ponto de falar. É trivial extrair essas informações usando o stringsutilitário para extrair todos os dados semelhantes a cadeias de caracteres do executável. Até os executáveis ​​compactados podem ser extraídos. Esteja atento ao que você envia para o site de um cliente. Muitas vezes, os concorrentes conseguem colocar as mãos em seus executáveis, mesmo que não devam fazê-lo.
Marty