Как получить только имя файла в препроцессоре?

Я использую (использую) макросы __FILE__ и __LINE__ для печати диагностических сообщений из моего кода. Это работает довольно хорошо, когда вы используете GCC с make, файл настолько короткий, насколько вы указали его в командной строке. Недавно я переключился на использование CodeLite, который использует полные имена файлов (по крайней мере, в Windows) при сборке. Внезапно мой диагностический вывод почти не читается.

Есть ли способ получить в препроцессоре только файловую составляющую имени файла? Я могу жить с непереносимым решением GCC. (Я вернусь к простым __FILE__ другим случаям.)

Конечно, я могу передать содержимое __FILE__ через функцию и извлечь только файловый компонент, но операции со строками — это не то, что я имел в виду для диагностических сообщений, которые не должны изменять поведение во время выполнения...

ПРИМЕЧАНИЕ. Я использую имя файла так, как его использует GNU. Путь — это набор имен файлов, а имя файла — относительный или абсолютный идентификатор файла. Имя файла может состоять из компонента каталога и компонента файла.


person rioki    schedule 13.09.2011    source источник
comment
Диагностика изменяет поведение во время выполнения (в противном случае диагностики не было бы), и не имеет большого значения, вызываете ли вы одну дополнительную функцию, поскольку сам вывод вызывает библиотечные функции для выполнения вывода в любом случае.   -  person eudoxos    schedule 13.09.2011
comment
Печать диагностического сообщения обычно включает в себя, в дополнение к десяткам строковых операций, некоторые не столь безобидные действия ввода-вывода файлов. Почему-то никто не беспокоится об этом. Зачем беспокоиться о добавлении вызова другой функции без побочных эффектов, которая влияет только на диагностические сообщения?   -  person n. 1.8e9-where's-my-share m.    schedule 13.09.2011
comment
Вы оба правы, добавление диагностики не бесплатно. Я реализовал это таким образом, я пропустил его через функцию. Мне было больше интересно, что что-то вроде этого существует. Это, конечно, не стандартно, но найти документацию по этому поводу не идеально. (Даже руководство gcc не описывает каждый предопределенный макрос.)   -  person rioki    schedule 19.09.2011
comment
О вводе/выводе; не каждая диагностика должна быть напечатана в STDOUT/STDERR или в файл. Вы когда-нибудь слышали о кольцевом буфере, который выводится при сбое приложения? Например, GNU Nana реализует это. В отличие от файлового ввода-вывода, это почти не влияет на производительность.   -  person rioki    schedule 19.09.2011
comment
К вашему сведению, есть также решение c++ constexpr: stackoverflow.com/a/38237385/52074   -  person Trevor Boyd Smith    schedule 14.05.2019


Ответы (4)


Если вы используете GNU Make, вы можете просто передать -D BASE_FILE_NAME=\"$*.c\" на этапе предварительной обработки компиляции (если вы делаете их отдельно, или при компиляции, если на одном этапе, что норма).

Это зависит от того, как вы определили имена файлов. Мои исходят из списка простых имен файлов и имеют префикс каталогов с использованием функций в make-файле на более позднем этапе.

IE, это хорошо работает для меня, но ваш пробег может отличаться! :-)

Упрощенная версия моего make "кода":

CLASSES = main.c init.c

PREPROCESSED = $(patsubst %.c,$(PPCDIR)/%.pp.c,$(CLASSES))

$(PREPROCESSED): $(PPCDIR)/%.pp.c: %.c $(ALLH) 
    $(GCC) $(GCCOPTS) -D BASE_FILE_NAME=\"$*\" -E $< > $@

Просто используйте BASE_FILE_NAME в своем коде, как вам нравится :-)

person FredCooke    schedule 16.11.2011
comment
К сожалению, я работаю с CodeLite, который генерирует для меня make-файлы. Использование CodeLite прекрасно, пока вы не захотите сделать что-то, выходящее за рамки нормы. Все еще хорошая идея, +1 - person rioki; 09.12.2011
comment
Ту же идею можно использовать в Visual Studio. В Visual Studio 2008: щелкните правой кнопкой мыши файл проекта (.vcproj) -> Свойства -> Свойства конфигурации -> C/C++ -> Препроцессор -> Определения препроцессора. Добавьте BASE_FILE__=\$(InputFileName)\. Вы можете использовать __BASE_FILE вместо FILE в исходных файлах. - person user720594; 28.11.2012

Не существует известного макроса препроцессора, обеспечивающего эту функциональность. Прохождение __FILE__ через функцию кажется единственным разумным вариантом.

person rioki    schedule 19.09.2011
comment
Для gcc есть __BASE_FILE__. - person fret; 15.06.2017
comment
@fret: для меня __BASE_FILE__ выводит то же, что и __FILE__. Если вы прочитали документацию, на которую вы ссылались, в ней указано имя (не обязательно базовое имя) файла с функцией main (даже не текущего файла). - person JellicleCat; 03.11.2017
comment
если вы можете использовать С++, тогда есть решение constexpr: stackoverflow.com/a/38237385/52074 - person Trevor Boyd Smith; 14.05.2019
comment
@TrevorBoydSmith хорошая мысль. Но, если честно, если вы посмотрите на дату, этот вопрос был задан через месяц после выпуска C++11 и еще не получил широкого распространения. - person rioki; 15.05.2019

В ответ FredCooke выше вы можете заменить эту строку:

-D BASE_FILE_NAME=\"$*.c\"

С:

-D BASE_FILE_NAME=\"$(<F)\"

Это даст вам правильное расширение имени файла, в том числе и для .cpp.

person Ying    schedule 12.12.2013

Как уже упоминалось в других ответах, единственный переносимый способ сделать это - передать определение из компилятора, однако существуют специальные расширения компилятора:

  • Звон: __FILE_NAME__
  • ССЗ: __BASE_FILE__
person ideasman42    schedule 20.09.2019