A macro predefinida padrão __FILE__disponível em C mostra o caminho completo para o arquivo. Existe alguma maneira de diminuir o caminho? Quero dizer em vez de
Seria realmente ótimo encontrar uma solução apenas para pré-processador. Receio que as sugestões baseadas em operações de string sejam executadas em tempo de execução.
Cdeonard
9
Como você está usando o gcc, acho que você pode alterar o __FILE__conteúdo, alterando o nome do arquivo que você passa na linha de comando. Então, em vez de gcc /full/path/to/file.c, tente cd /full/path/to; gcc file.c; cd -;. Claro que há um pouco mais do que isso, se você estiver contando com o diretório atual do gcc para o caminho de inclusão ou o local do arquivo de saída. Edit: os documentos do gcc sugerem que é o caminho completo, não o argumento do nome do arquivo de entrada, mas não é isso que estou vendo no gcc 4.5.3 no Cygwin. Então você pode tentar no Linux e ver.
precisa
4
O GCC 4.5.1 (criado especificamente para arm-none-eabi) usa o texto exato do nome do arquivo em sua linha de comando. No meu caso, foi culpa do IDE invocar o GCC com todos os nomes de arquivos totalmente qualificados, em vez de colocar o diretório atual em algum lugar sensato (local do arquivo do projeto, talvez?) Ou configurável e usar caminhos relativos a partir daí. Suspeito que muitos IDEs façam isso (especialmente no Windows) devido a algum tipo de desconforto relacionado à explicação de onde o diretório "atual" realmente é para um aplicativo GUI.
RBerteig 13/09/12
3
@SteveJessop - espero que você leia este comentário. Eu tenho uma situação em que vejo __FILE__impressa como ../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.ce quero saber onde o gcc compilou o arquivo, de modo que esse arquivo esteja relativamente localizado, como é mostrado.
Chan Kim
1
Esta questão não é uma mentira da vinculada. Por um lado, o vinculado é sobre C ++, e as respostas, consequentemente, se aprofundam na macro esotérica C ++. Segundo, nada na pergunta do OP exige uma solução macro. Apenas aponta solenemente um problema e faz uma pergunta em aberto.
/é um separador de caminho válido nos nomes de arquivos passados para CreateFile () e assim por diante. No entanto, isso nem sempre significa que você pode usar /em qualquer lugar do Windows, já que existe uma tradição (herdada do CPM) de usar /como argumento no prompt de comando. Mas uma ferramenta de qualidade teria o cuidado de dividir os nomes dos arquivos nos caracteres barra e barra invertida para evitar problemas para as pessoas que conseguem usar /.
RBerteig 13/09/12
5
@AmigableClarkKant, não, você pode misturar os dois separadores com o mesmo nome de arquivo.
RBerteig 13/09/12
2
Se a sua plataforma suporta, char* fileName = basename(__FILE__); definitivamente está lá no Linux e no OS X, embora não conheça o Windows.
JeremyP
14
Isso pode ser reduzido para strrchr("/" __FILE__, '/') + 1. Ao adicionar "/" a __FILE__, strrchr será garantido que encontrará algo e, portanto, o condicional?: Não será mais necessário.
Se você estiver usando o GNU make, não vejo razão para que você não possa estender isso para seus próprios makefiles. Por exemplo, você pode ter uma linha como esta:
Receio que isso não funcione para o arquivo referenciado no arquivo de cabeçalho.
Baiyan Huang 12/09
2
Concorde com @BaiyanHuang, mas não tenha certeza de que o comentário é claro. __FILE__não é um símbolo simples de pré-processador, é alterado frequentemente para o arquivo atual para emitir o nome do arquivo atual (cabeçalho ou módulo de origem). Isso __FILENAME__teria apenas a fonte mais externa
encerrada
3
A solução desta resposta não é portátil, pois usa escapes de shell Bourne. Melhor usar o CMake para implementá-lo de maneira limpa e portátil. Consulte a resposta da macro define_file_basename_for_sources aqui.
Colin D Bennett
3
A variante GNU Make disso é CFLAGS + = -D__FILENAME __ = \ "$ (notdir $ <) \"
ctuffli
4
@firegurafiku Em plataformas incorporadas, o tamanho do código geralmente é mais uma restrição do que velocidade. Se você tiver instruções de depuração em cada arquivo, isso pode aumentar rapidamente o tamanho do arquivo com cadeias de caracteres de caminho completo. Estou lidando com essa plataforma no momento e a referência a __FILE__todos os lugares está saindo do espaço do código.
Mrtumnus
26
Acabei de pensar em uma ótima solução para isso, que funciona com os arquivos de origem e de cabeçalho, é muito eficiente e funciona em tempo de compilação em todas as plataformas sem extensões específicas do compilador. Essa solução também preserva a estrutura de diretórios relativa do seu projeto, para que você saiba em qual pasta o arquivo está e apenas em relação à raiz do seu projeto.
A idéia é obter o tamanho do diretório de origem com sua ferramenta de construção e apenas adicioná-lo à __FILE__macro, removendo o diretório completamente e mostrando apenas o nome do arquivo começando no diretório de origem.
O exemplo a seguir é implementado usando o CMake, mas não há razão para que ele não funcione com outras ferramentas de construção, porque o truque é muito simples.
No arquivo CMakeLists.txt, defina uma macro que tenha o comprimento do caminho para o seu projeto no CMake:
# The additional / is important to remove the last character from the path.# Note that it does not matter if the OS uses / or \, because we are only# saving the path size.
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
No seu código-fonte, defina uma __FILENAME__macro que apenas adicione o tamanho do caminho de origem à __FILE__macro:
Em seguida, basta usar essa nova macro em vez da __FILE__macro. Isso funciona porque o __FILE__caminho sempre começa com o caminho para o diretório de origem do CMake. Ao removê-lo da __FILE__string, o pré-processador se encarregará de especificar o nome correto do arquivo e tudo será relativo à raiz do seu projeto CMake.
Se você se preocupa com o desempenho, este é tão eficiente quanto usar __FILE__, porque ambos __FILE__e SOURCE_PATH_SIZEsão conhecidos constantes de tempo de compilação, para que possa ser otimizado afastado pelo compilador.
O único lugar em que isso falharia é se você estiver usando isso em arquivos gerados e eles estiverem em uma pasta de compilação externa. Então você provavelmente terá que criar outra macro usando a CMAKE_BUILD_DIRvariável em vez de CMAKE_SOURCE_DIR.
Eu não entendi isso no começo. Eu codifiquei exemplos e os executei contra o gcc e o clang, e eles funcionam. Também experimento anexar vários valores numéricos literais, e isso se comporta como eu esperava. Então finalmente me ocorreu. __FILE__é um ponteiro para uma matriz de bytes. Portanto, adicionar um literal numérico é apenas uma adição de ponteiro. Muito inteligente @RenatoUtsch
Daniel
Funciona apenas se um arquivo de origem estiver no diretório cmake list. Se um arquivo de origem estiver fora, ele será interrompido, com acesso fora de uma cadeia literal. Portanto, tenha cuidado com isso.
Andry
Na verdade, não reduz o tamanho do código. Eu acho que todo o caminho ainda está compilado no binário, apenas o ponteiro é modificado.
Tarion
A __FILE__macro e as macros SOURCE_PATH_SIZE são constantes conhecidas em tempo de compilação. Eu esperaria que os compiladores de otimização modernos pudessem detectar que parte da string não é usada e simplesmente removê-la do binário. De qualquer forma, não acho que esses poucos bytes fariam uma diferença significativa no tamanho binário, então eu realmente não me importo com isso.
RenatoUtsch 20/02/19
@RenatoUtsch O projeto no qual estou trabalhando tem uma alteração que apenas especifica o nome do arquivo, mas tem a desvantagem de atribuir o nome do arquivo C ao cabeçalho também. A alteração foi feita para obter compilações reproduzíveis. Então, com o gcc com -O2, a string seria realmente otimizada e a compilação tornada reproduzível?
Paul Stelian
18
Compile a solução de tempo aqui. É baseado no fato de que sizeof()uma string literal retorna seu comprimento + 1.
Sinta-se à vontade para estender a cascata condicional do operador até o nome máximo de arquivo sensível no projeto. O comprimento do caminho não importa, desde que você verifique o suficiente a partir do final da string.
Vou ver se consigo obter uma macro semelhante sem comprimento codificado com recursão de macro ...
Resposta legal. Você precisa usar pelo menos -O1para usar isso em tempo de compilação.
Digital Trauma
1
Não é isso ao contrário? Você deseja encontrar a última ocorrência de '/', o que significa que você deve começar sizeof(s) > 2primeiro com a verificação. Além disso, isso não funcionou em tempo de compilação para mim, no -Os. As cadeias de caminho completo estavam presentes no binário de saída.
Mrtumnus
15
Pelo menos para gcc, o valor de __FILE__é o caminho do arquivo, conforme especificado na linha de comando do compilador . Se você compilar file.cassim:
gcc -c /full/path/to/file.c
a __FILE__ expandirá para "/full/path/to/file.c". Se você fizer isso:
cd /full/path/to
gcc -c file.c
então __FILE__será expandido para apenas "file.c".
Isso pode ou não ser prático.
O padrão C não requer esse comportamento. Tudo o que diz sobre__FILE__ é que ele se expande para "O nome presumido do arquivo de origem atual (uma literal de cadeia de caracteres)".
Uma alternativa é usar o #line diretiva. Ele substitui o número da linha atual e, opcionalmente, o nome do arquivo de origem. Se você deseja substituir o nome do arquivo, mas deixar o número da linha em branco, use a __LINE__macro.
Por exemplo, você pode adicionar isso próximo ao topo de file.c:
#line __LINE__ "file.c"
O único problema disso é que ele atribui o número da linha especificada à linha a seguir e o primeiro argumento #linedeve ser uma sequência de dígitos, para que você não possa fazer algo como
#line(__LINE__-1)"file.c"// This is invalid
Assegurando que o nome do arquivo no #line diretiva corresponda ao nome real do arquivo seja deixado como um exercício.
Pelo menos para o gcc, isso também afetará o nome do arquivo relatado nas mensagens de diagnóstico.
Keith Thompson, é uma ótima solução, obrigado. O único problema é que parece que essa macro reduz o __LINE__valor em um. Então, __LINE__escrito em linha xgest avaliado como x-1. Pelo menos com o gcc 5.4.
Elbowpo #
1
@Klepak: Você está certo, e esse é o comportamento padrão. A diretiva "faz com que a implementação se comporte como se a seguinte sequência de linhas de origem começasse com uma linha de origem que tenha um número de linha especificado pela sequência de dígitos". E tem que ser uma sequência de dígitos , para que você não possa usar #line __LINE__-1, "file.c". Vou atualizar minha resposta.
9788 Keith Thompson #
1
Como seria para outros compiladores como Clang, MSVC ou Intel C Compiler?
Franklin Yu
8
Um pouco atrasado para a festa, mas para o GCC dê uma olhada na -ffile-prefix-map=old=newopção:
Ao compilar arquivos que residem no diretório antigo , registre todas as referências a eles no resultado da compilação como se os arquivos residissem no diretório novo . Especificar esta opção é equivalente a especificar todas as -f*-prefix-mapopções individuais . Isso pode ser usado para criar construções reproduzíveis independentes do local. Veja também
-fmacro-prefix-mape -fdebug-prefix-map.
Portanto, para minhas compilações Jenkins , adicionarei uma -ffile-prefix-map=${WORKSPACE}/=/outra para remover o prefixo local de instalação do pacote de desenvolvimento.
OBSERVAÇÃO Infelizmente, a -ffile-prefix-mapopção só está disponível no GCC 8 em diante, como é o -fmacro-prefix-mapque, penso eu , faz a __FILE__parte. Por exemplo, no GCC 5, temos apenas o -fdebug-prefix-mapque não parece (afetar) __FILE__.
template<typename T,size_t S>inlineconstexprsize_t get_file_name_offset(const T (& str)[S],size_t i = S -1){return(str[i]=='/'|| str[i]=='\\')? i +1:(i >0? get_file_name_offset(str, i -1):0);}template<typename T>inlineconstexprsize_t get_file_name_offset(T (& str)[1]){return0;}
"
int main(){
printf("%s\n",&__FILE__[get_file_name_offset(__FILE__)]);}
O código gera um deslocamento do tempo de compilação quando:
clang: persiste na não compilação da avaliação do tempo
Existe um truque para forçar todos os 3 compiladores a compilarem a avaliação do tempo, mesmo na configuração de depuração com otimização desabilitada:
namespace utility {template<typename T, T v>struct const_expr_value
{staticconstexprconst T value = v;};}#define UTILITY_CONST_EXPR_VALUE(exp)::utility::const_expr_value<decltype(exp), exp>::value
int main(){
printf("%s\n",&__FILE__[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(__FILE__))]);}
Não há tempo de compilação para fazer isso. Obviamente, você pode fazê-lo em tempo de execução usando o tempo de execução C, como algumas das outras respostas demonstraram, mas em tempo de compilação, quando o pré-processador entrar em ação, você estará sem sorte.
a strrchrresposta poderia ser plausivelmente calculada em tempo de compilação, embora, é claro, ainda não o seja pelo pré-processador. Não sei se o gcc realmente faz isso, não verifiquei, mas tenho certeza de que ele calcula strlenliterais de strings em tempo de compilação.
precisa
@ Steve - talvez, mas essa é uma grande dependência do comportamento específico do compilador.
Sean
Não acho que seja uma grande dependência, porque duvido muito que esse código seja crítico para o desempenho. E se for, mova-o para fora do loop. Nos casos em que isso é um grande negócio, porque você absolutamente precisa de uma literal de cadeia contendo apenas o nome da base, talvez possa computar a cadeia correta no tempo de construção executando algum script na fonte.
precisa
5
Pode não ser crítico para o desempenho, mas pode ser facilmente visto como crítico para a privacidade. Não há uma boa razão para revelar minhas práticas organizacionais por cliente em sequências congeladas em um arquivo EXE liberado. Pior, para aplicativos criados em nome de um cliente, essas sequências de caracteres podem revelar coisas que meu cliente prefere não, como não ser o autor de seu próprio produto. Como __FILE__é invocado implicitamente por assert(), esse vazamento pode ocorrer sem nenhum outro ato manifesto.
RBerteig 13/09/12
O @RBerteig, o __FILE__próprio nome da base , também pode revelar coisas que o cliente pode preferir, portanto, o uso de __FILE__qualquer lugar - se ele contém o nome do caminho absoluto completo ou apenas o nome da base - tem os mesmos problemas que você apontou. Nessa situação, toda a saída precisará ser examinada e uma API especial deve ser introduzida para a saída dos clientes. O restante da saída deve ser descarregado para / dev / NULL ou stdout e o stderr deve ser fechado. :-)
@mahmood: char file_copy[] = __FILE__; const char *filename = basename(__FILE__);. O motivo da cópia é que o nome da base pode modificar a sequência de entrada. Você também deve observar que o ponteiro do resultado só é bom até que basenameseja chamado novamente. Isso significa que não é seguro para threads.
precisa
@ SteveJessop, ah eu esqueci. Verdade.
Prof. Falken
1
@ Amigable: para ser justo, suspeito que basename, de fato, não modifique a string de entrada resultante __FILE__, porque a string de entrada não possui um /no final e, portanto, não há necessidade de modificação. Então você pode se safar, mas acho que na primeira vez que alguém vê basename, deve vê-lo com todas as restrições.
18711 Steve Jobs (
@SteveJessop, a página de manual do BSd para basename () menciona que a versão herdada de basename () recebe um const char * e não modifica a string. A página de manual do linux não menciona nada sobre const, mas menciona que ele pode retornar uma parte da sequência de argumentos. Portanto, é melhor ser conservador ao lidar com basename ().
Prof. Falken
@SteveJessop, hehe, só agora, depois de analisar seu comentário com cuidado, depois de quatro anos, percebo que /no final da string significa que basename pode ter um bom motivo para modificar seu argumento.
Prof. Falken
4
Se você estiver usando o CMAKEcompilador GNU, isso globaldefine bem:
-Wno-builtin-macro-redefinedpara silenciar os avisos do compilador para redefinir a __FILE__macro.
Para esses compiladores não suportam isso, consulte a maneira Robusta abaixo.
Tirar o caminho do projeto do caminho do arquivo é o seu requisito real . Você não vai gostar de perder tempo para descobrir onde está um header.harquivo src/foo/header.hou src/bar/header.h.
Devemos tirar a __FILE__macrocmake arquivo de configuração.
Essa macro é usada na maioria dos códigos existentes. Simplesmente redefina que pode liberar você.
Compiladores como gccpredefinem essa macro a partir dos argumentos da linha de comando. E o caminho completo é escrito em makefiles gerado por cmake.
CMAKE_*_FLAGSÉ necessário o código rígido .
Existem alguns comandos para adicionar opções ou definições do compilador em uma versão mais recente, como add_definitions()e add_compile_definitions(). Esses comandos analisam as funções make, como substantes se aplicam aos arquivos de origem. Não é isso que queremos.
Maneira robusta para -Wno-builtin-macro-redefined.
Isso não funciona para conteúdos provenientes de arquivos de inclusão.
chqrlie 30/03
Pode postar algum código? Um caso comum é definir variáveis no escopo local e usá-las em outro.
Levi.G
Por exemplo, se você usar __FILE__com sua definição para produzir um diagnóstico em uma função embutida definida em um arquivo de cabeçalho, o diagnóstico de tempo de execução relatará o nome do arquivo passado ao compilador em vez do nome do arquivo de inclusão, enquanto o número da linha seria consulte o arquivo de inclusão.
chqrlie 10/04
Sim, ele foi projetado para isso, para o uso mais comum #define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args). ao usar a LOG()macro, você realmente não deseja ver log.hnas mensagens. afinal, a __FILE__macro é expandida em todos os arquivos C / Cpp (unidade de compilação) em vez dos arquivos incluídos.
Levi.G 14/06
3
Uma pequena variação do que o @ red1ynx proposto criaria a seguinte macro:
Eu fiz uma macro __FILENAME__ que evita cortar caminho completo a cada vez. O problema é manter o nome do arquivo resultante em uma variável local cpp.
Isso pode ser feito facilmente, definindo uma variável global estática no arquivo .h . Essa definição fornece variáveis separadas e independentes em cada arquivo .cpp que inclui o arquivo .h . Para ser uma prova de multithreading, vale a pena fazer com que a (s) variável (s) também encadeie (TLS) local.
Uma variável armazena o nome do arquivo (reduzido). Outro detém o valor não cortado que __FILE__deu. O arquivo h:
constchar*GetSourceFileName(constchar* strFilePath,constchar*& rstrFilePathHolder,constchar*& rstrFileNameHolder){if(strFilePath != rstrFilePathHolder){// // This if works in 2 cases: // - when first time called in the cpp (ordinary case) or// - when the macro __FILENAME__ is used in both h and cpp files // and so the method is consequentially called // once with strFilePath == "UserPath/HeaderFileThatUsesMyMACRO.h" and // once with strFilePath == "UserPath/CPPFileThatUsesMyMACRO.cpp"//
rstrFileNameHolder = removePath(strFilePath);
rstrFilePathHolder = strFilePath;}return rstrFileNameHolder;}
O removePath () pode ser implementado de diferentes maneiras, mas o rápido e o simples parecem estar com o strrchr:
push_macroe pop_macronão são padrão. (O gcc oferece suporte a eles para compatibilidade com os compiladores do Microsoft Windows.) De qualquer forma, não faz sentido empurrar e exibir a definição de __FILE__; o valor restaurado não será usado após o final do arquivo de origem. A maneira mais limpa para alterar o valor de __FILE__é#line __LINE__ "foobar.c"
Se você acabou nesta página procurando uma maneira de remover o caminho de origem absoluto que está apontando para o local de criação feio do binário que você está enviando, abaixo pode atender às suas necessidades.
Embora isso não produza exatamente a resposta que o autor expressou seu desejo, pois pressupõe o uso do CMake , ele fica bem próximo. É uma pena que isso não tenha sido mencionado anteriormente por ninguém, pois teria me poupado muito tempo.
OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)
A configuração acima da variável para ONgerará o comando build no formato:
cd /ugly/absolute/path/to/project/build/src &&
gcc <.. other flags ..>-c ../../src/path/to/source.c
Como resultado, a __FILE__macro resolverá../../src/path/to/source.c
A documentação do CMake 3.4 ou superior afirma que "Esta variável não tem efeito. O efeito parcialmente implementado que possuía nas versões anteriores foi removido no CMake 3.4". Se funcionou para você com 3.13, há outra razão para isso.
mike.dld
0
Como você está usando o GCC, você pode tirar proveito de
__BASE_FILE__Essa macro se expande para o nome do arquivo de entrada principal, na forma de uma constante de seqüência C. Este é o arquivo de origem especificado na linha de comandos do pré-processador ou compilador C
e depois controle como você deseja exibir o nome do arquivo alterando a representação do arquivo de origem (caminho completo / caminho relativo / nome da base) no momento da compilação.
Não faz diferença. Eu usei __FILE__e __BASE_FILE__no entanto ambos mostrar caminho completo para arquivo
mahmood
como você chama o compilador?
Ziu
2
Então aposto que o SCONS está chamando gcc assim gcc /absolute/path/to/file.c. Se você encontrar uma maneira de alterar esse comportamento (? Abrindo uma outra pergunta sobre SO, lol), você não precisa de modificar a cadeia em tempo de execução
ziu
17
Esta resposta está 100% errada. __BASE_FILE__(como dizem os documentos, embora sem clareza) produz o nome do arquivo especificado na linha de comando , por exemplo, test.cou /tmp/test.cdependendo de como você chamou o compilador. É exatamente a mesma coisa que __FILE__, exceto se você estiver dentro de um arquivo de cabeçalho, caso em que __FILE__produz o nome do arquivo atual (por exemplo foo.h) enquanto __BASE_FILE__continua a produzir test.c.
Quuxplusone
0
Aqui está uma solução que funciona para ambientes que não possuem a biblioteca de strings (kernel do Linux, sistemas incorporados etc.):
Pode querer verificar '/' e '\', dependendo da plataforma.
31518
0
#include<algorithm>#include<string>usingnamespace std;
string f( __FILE__ );
f = string((find(f.rbegin(), f.rend(),'/')+1).base()+1, f.end());// searches for the '/' from the back, transfers the reverse iterator // into a forward iterator and constructs a new sting with both
__FILE__
conteúdo, alterando o nome do arquivo que você passa na linha de comando. Então, em vez degcc /full/path/to/file.c
, tentecd /full/path/to; gcc file.c; cd -;
. Claro que há um pouco mais do que isso, se você estiver contando com o diretório atual do gcc para o caminho de inclusão ou o local do arquivo de saída. Edit: os documentos do gcc sugerem que é o caminho completo, não o argumento do nome do arquivo de entrada, mas não é isso que estou vendo no gcc 4.5.3 no Cygwin. Então você pode tentar no Linux e ver.__FILE__
impressa como../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.c
e quero saber onde o gcc compilou o arquivo, de modo que esse arquivo esteja relativamente localizado, como é mostrado.Respostas:
Experimentar
Para Windows, use '\\' em vez de '/'.
fonte
/
é um separador de caminho válido no Windows./
é um separador de caminho válido nos nomes de arquivos passados para CreateFile () e assim por diante. No entanto, isso nem sempre significa que você pode usar/
em qualquer lugar do Windows, já que existe uma tradição (herdada do CPM) de usar/
como argumento no prompt de comando. Mas uma ferramenta de qualidade teria o cuidado de dividir os nomes dos arquivos nos caracteres barra e barra invertida para evitar problemas para as pessoas que conseguem usar/
.char* fileName = basename(__FILE__);
definitivamente está lá no Linux e no OS X, embora não conheça o Windows.strrchr("/" __FILE__, '/') + 1
. Ao adicionar "/" a__FILE__
, strrchr será garantido que encontrará algo e, portanto, o condicional?: Não será mais necessário.Aqui está uma dica se você estiver usando o cmake. De: http://public.kitware.com/pipermail/cmake/2013-January/053117.html
Estou copiando a dica, então está tudo nesta página:
Se você estiver usando o GNU make, não vejo razão para que você não possa estender isso para seus próprios makefiles. Por exemplo, você pode ter uma linha como esta:
onde
$(SOURCE_PREFIX)
é o prefixo que você deseja remover.Em seguida, use
__FILENAME__
no lugar de__FILE__
.fonte
__FILE__
não é um símbolo simples de pré-processador, é alterado frequentemente para o arquivo atual para emitir o nome do arquivo atual (cabeçalho ou módulo de origem). Isso__FILENAME__
teria apenas a fonte mais externa__FILE__
todos os lugares está saindo do espaço do código.Acabei de pensar em uma ótima solução para isso, que funciona com os arquivos de origem e de cabeçalho, é muito eficiente e funciona em tempo de compilação em todas as plataformas sem extensões específicas do compilador. Essa solução também preserva a estrutura de diretórios relativa do seu projeto, para que você saiba em qual pasta o arquivo está e apenas em relação à raiz do seu projeto.
A idéia é obter o tamanho do diretório de origem com sua ferramenta de construção e apenas adicioná-lo à
__FILE__
macro, removendo o diretório completamente e mostrando apenas o nome do arquivo começando no diretório de origem.O exemplo a seguir é implementado usando o CMake, mas não há razão para que ele não funcione com outras ferramentas de construção, porque o truque é muito simples.
No arquivo CMakeLists.txt, defina uma macro que tenha o comprimento do caminho para o seu projeto no CMake:
No seu código-fonte, defina uma
__FILENAME__
macro que apenas adicione o tamanho do caminho de origem à__FILE__
macro:Em seguida, basta usar essa nova macro em vez da
__FILE__
macro. Isso funciona porque o__FILE__
caminho sempre começa com o caminho para o diretório de origem do CMake. Ao removê-lo da__FILE__
string, o pré-processador se encarregará de especificar o nome correto do arquivo e tudo será relativo à raiz do seu projeto CMake.Se você se preocupa com o desempenho, este é tão eficiente quanto usar
__FILE__
, porque ambos__FILE__
eSOURCE_PATH_SIZE
são conhecidos constantes de tempo de compilação, para que possa ser otimizado afastado pelo compilador.O único lugar em que isso falharia é se você estiver usando isso em arquivos gerados e eles estiverem em uma pasta de compilação externa. Então você provavelmente terá que criar outra macro usando a
CMAKE_BUILD_DIR
variável em vez deCMAKE_SOURCE_DIR
.fonte
__FILE__
é um ponteiro para uma matriz de bytes. Portanto, adicionar um literal numérico é apenas uma adição de ponteiro. Muito inteligente @RenatoUtsch__FILE__
macro e as macros SOURCE_PATH_SIZE são constantes conhecidas em tempo de compilação. Eu esperaria que os compiladores de otimização modernos pudessem detectar que parte da string não é usada e simplesmente removê-la do binário. De qualquer forma, não acho que esses poucos bytes fariam uma diferença significativa no tamanho binário, então eu realmente não me importo com isso.Compile a solução de tempo aqui. É baseado no fato de que
sizeof()
uma string literal retorna seu comprimento + 1.Sinta-se à vontade para estender a cascata condicional do operador até o nome máximo de arquivo sensível no projeto. O comprimento do caminho não importa, desde que você verifique o suficiente a partir do final da string.
Vou ver se consigo obter uma macro semelhante sem comprimento codificado com recursão de macro ...
fonte
-O1
para usar isso em tempo de compilação.sizeof(s) > 2
primeiro com a verificação. Além disso, isso não funcionou em tempo de compilação para mim, no -Os. As cadeias de caminho completo estavam presentes no binário de saída.Pelo menos para gcc, o valor de
__FILE__
é o caminho do arquivo, conforme especificado na linha de comando do compilador . Se você compilarfile.c
assim:a
__FILE__
expandirá para"/full/path/to/file.c"
. Se você fizer isso:então
__FILE__
será expandido para apenas"file.c"
.Isso pode ou não ser prático.
O padrão C não requer esse comportamento. Tudo o que diz sobre
__FILE__
é que ele se expande para "O nome presumido do arquivo de origem atual (uma literal de cadeia de caracteres)".Uma alternativa é usar o
#line
diretiva. Ele substitui o número da linha atual e, opcionalmente, o nome do arquivo de origem. Se você deseja substituir o nome do arquivo, mas deixar o número da linha em branco, use a__LINE__
macro.Por exemplo, você pode adicionar isso próximo ao topo de
file.c
:O único problema disso é que ele atribui o número da linha especificada à linha a seguir e o primeiro argumento
#line
deve ser uma sequência de dígitos, para que você não possa fazer algo comoAssegurando que o nome do arquivo no
#line
diretiva corresponda ao nome real do arquivo seja deixado como um exercício.Pelo menos para o gcc, isso também afetará o nome do arquivo relatado nas mensagens de diagnóstico.
fonte
__LINE__
valor em um. Então,__LINE__
escrito em linhax
gest avaliado comox-1
. Pelo menos com o gcc 5.4.#line __LINE__-1, "file.c"
. Vou atualizar minha resposta.Um pouco atrasado para a festa, mas para o GCC dê uma olhada na
-ffile-prefix-map=old=new
opção:Portanto, para minhas compilações Jenkins , adicionarei uma
-ffile-prefix-map=${WORKSPACE}/=/
outra para remover o prefixo local de instalação do pacote de desenvolvimento.OBSERVAÇÃO Infelizmente, a
-ffile-prefix-map
opção só está disponível no GCC 8 em diante, como é o-fmacro-prefix-map
que, penso eu , faz a__FILE__
parte. Por exemplo, no GCC 5, temos apenas o-fdebug-prefix-map
que não parece (afetar)__FILE__
.fonte
-ffile-prefix-map
fato implica ambos-fdebug-prefix-map
e-fmacro-prefix-map
opções. Veja também as referências em reproducible-builds.org/docs/build-path O bug do GCC que rastreia-fmacro-prefix-map
e-ffile-prefix-map
é gcc.gnu.org/bugzilla/show_bug.cgi?id=70268msvc2015u3, gcc5.4, clang3.8.0
"
O código gera um deslocamento do tempo de compilação quando:
gcc
: pelo menos gcc6.1 +-O1
msvc
: colocar resultado na variável constexpr:clang
: persiste na não compilação da avaliação do tempoExiste um truque para forçar todos os 3 compiladores a compilarem a avaliação do tempo, mesmo na configuração de depuração com otimização desabilitada:
https://godbolt.org/z/u6s8j3
fonte
No VC, ao usar
/FC
,__FILE__
expande para o caminho completo, sem a/FC
opção__FILE__
expande o nome do arquivo. ref: aquifonte
Não há tempo de compilação para fazer isso. Obviamente, você pode fazê-lo em tempo de execução usando o tempo de execução C, como algumas das outras respostas demonstraram, mas em tempo de compilação, quando o pré-processador entrar em ação, você estará sem sorte.
fonte
strrchr
resposta poderia ser plausivelmente calculada em tempo de compilação, embora, é claro, ainda não o seja pelo pré-processador. Não sei se o gcc realmente faz isso, não verifiquei, mas tenho certeza de que ele calculastrlen
literais de strings em tempo de compilação.__FILE__
é invocado implicitamente porassert()
, esse vazamento pode ocorrer sem nenhum outro ato manifesto.__FILE__
próprio nome da base , também pode revelar coisas que o cliente pode preferir, portanto, o uso de__FILE__
qualquer lugar - se ele contém o nome do caminho absoluto completo ou apenas o nome da base - tem os mesmos problemas que você apontou. Nessa situação, toda a saída precisará ser examinada e uma API especial deve ser introduzida para a saída dos clientes. O restante da saída deve ser descarregado para / dev / NULL ou stdout e o stderr deve ser fechado. :-)Use a função basename () ou, se você estiver no Windows, _splitpath () .
Tente também
man 3 basename
em uma concha.fonte
char file_copy[] = __FILE__; const char *filename = basename(__FILE__);
. O motivo da cópia é que o nome da base pode modificar a sequência de entrada. Você também deve observar que o ponteiro do resultado só é bom até quebasename
seja chamado novamente. Isso significa que não é seguro para threads.basename
, de fato, não modifique a string de entrada resultante__FILE__
, porque a string de entrada não possui um/
no final e, portanto, não há necessidade de modificação. Então você pode se safar, mas acho que na primeira vez que alguém vêbasename
, deve vê-lo com todas as restrições./
no final da string significa que basename pode ter um bom motivo para modificar seu argumento.Se você estiver usando o
CMAKE
compilador GNU, issoglobal
define bem:fonte
Eu uso a mesma solução com a resposta do @Patrick há anos.
Há um pequeno problema quando o caminho completo contém um link de símbolo.
Melhor solução.
Por que usar isso?
-Wno-builtin-macro-redefined
para silenciar os avisos do compilador para redefinir a__FILE__
macro.Tirar o caminho do projeto do caminho do arquivo é o seu requisito real . Você não vai gostar de perder tempo para descobrir onde está um
header.h
arquivosrc/foo/header.h
ousrc/bar/header.h
.Devemos tirar a
__FILE__
macrocmake
arquivo de configuração.Essa macro é usada na maioria dos códigos existentes. Simplesmente redefina que pode liberar você.
Compiladores como
gcc
predefinem essa macro a partir dos argumentos da linha de comando. E o caminho completo é escrito emmakefile
s gerado porcmake
.CMAKE_*_FLAGS
É necessário o código rígido .Existem alguns comandos para adicionar opções ou definições do compilador em uma versão mais recente, como
add_definitions()
eadd_compile_definitions()
. Esses comandos analisam as funções make, comosubst
antes se aplicam aos arquivos de origem. Não é isso que queremos.Maneira robusta para
-Wno-builtin-macro-redefined
.fonte
__FILE__
com sua definição para produzir um diagnóstico em uma função embutida definida em um arquivo de cabeçalho, o diagnóstico de tempo de execução relatará o nome do arquivo passado ao compilador em vez do nome do arquivo de inclusão, enquanto o número da linha seria consulte o arquivo de inclusão.#define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args)
. ao usar aLOG()
macro, você realmente não deseja verlog.h
nas mensagens. afinal, a__FILE__
macro é expandida em todos os arquivos C / Cpp (unidade de compilação) em vez dos arquivos incluídos.Uma pequena variação do que o @ red1ynx proposto criaria a seguinte macro:
Em cada um dos seus arquivos .c (pp), adicione:
Então você pode consultar em
THIS_FILE_NAME
vez de__FILE__
:Isso significa que a construção é executada uma vez por arquivo .c (pp) em vez de cada vez que a macro é referenciada.
É limitado a usar apenas de arquivos .c (pp) e não pode ser usado nos arquivos de cabeçalho.
fonte
Eu fiz uma macro
__FILENAME__
que evita cortar caminho completo a cada vez. O problema é manter o nome do arquivo resultante em uma variável local cpp.Isso pode ser feito facilmente, definindo uma variável global estática no arquivo .h . Essa definição fornece variáveis separadas e independentes em cada arquivo .cpp que inclui o arquivo .h . Para ser uma prova de multithreading, vale a pena fazer com que a (s) variável (s) também encadeie (TLS) local.
Uma variável armazena o nome do arquivo (reduzido). Outro detém o valor não cortado que
__FILE__
deu. O arquivo h:A própria macro chama método com toda a lógica:
E a função é implementada desta maneira:
O removePath () pode ser implementado de diferentes maneiras, mas o rápido e o simples parecem estar com o strrchr:
fonte
O compilador Clang recente possui uma
__FILE_NAME__
macro (veja aqui ).fonte
só espero melhorar um pouco a macro FILE:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
isso captura / e \, como Czarek Tomczak solicitou, e funciona muito bem no meu ambiente misto.
fonte
FILE
é uma péssima idéia, se você incluir<stdio.h>
.Experimentar
após as instruções de inclusão no seu arquivo de origem e adicione
no final do seu arquivo de origem.
fonte
push_macro
epop_macro
não são padrão. (O gcc oferece suporte a eles para compatibilidade com os compiladores do Microsoft Windows.) De qualquer forma, não faz sentido empurrar e exibir a definição de__FILE__
; o valor restaurado não será usado após o final do arquivo de origem. A maneira mais limpa para alterar o valor de__FILE__
é#line __LINE__ "foobar.c"
Aqui está uma função portátil que funciona para Linux (caminho '/') e Windows (combinação de '\' e '/').
Compila com gcc, clang e vs.
Saída padrão:
fonte
Aqui está a solução que usa o cálculo em tempo de compilação:
fonte
Se você acabou nesta página procurando uma maneira de remover o caminho de origem absoluto que está apontando para o local de criação feio do binário que você está enviando, abaixo pode atender às suas necessidades.
Embora isso não produza exatamente a resposta que o autor expressou seu desejo, pois pressupõe o uso do CMake , ele fica bem próximo. É uma pena que isso não tenha sido mencionado anteriormente por ninguém, pois teria me poupado muito tempo.
A configuração acima da variável para
ON
gerará o comando build no formato:Como resultado, a
__FILE__
macro resolverá../../src/path/to/source.c
Documentação do CMake
Cuidado com o aviso na página de documentação:
Não é garantido que funcione em todos os casos, mas funcionou no meu - CMake 3.13 + gcc 4.5
fonte
Como você está usando o GCC, você pode tirar proveito de
e depois controle como você deseja exibir o nome do arquivo alterando a representação do arquivo de origem (caminho completo / caminho relativo / nome da base) no momento da compilação.
fonte
__FILE__
e__BASE_FILE__
no entanto ambos mostrar caminho completo para arquivogcc /absolute/path/to/file.c
. Se você encontrar uma maneira de alterar esse comportamento (? Abrindo uma outra pergunta sobre SO, lol), você não precisa de modificar a cadeia em tempo de execução__BASE_FILE__
(como dizem os documentos, embora sem clareza) produz o nome do arquivo especificado na linha de comando , por exemplo,test.c
ou/tmp/test.c
dependendo de como você chamou o compilador. É exatamente a mesma coisa que__FILE__
, exceto se você estiver dentro de um arquivo de cabeçalho, caso em que__FILE__
produz o nome do arquivo atual (por exemplofoo.h
) enquanto__BASE_FILE__
continua a produzirtest.c
.Aqui está uma solução que funciona para ambientes que não possuem a biblioteca de strings (kernel do Linux, sistemas incorporados etc.):
Agora basta usar em
FILENAME
vez de__FILENAME__
. Sim, ainda é uma coisa de tempo de execução, mas funciona.fonte
fonte
Uma resposta curta e funcional para Windows e * nix:
fonte
std::max<const char*>
vez de apenasstd::max
?