17 ответов:
попробовать
#include <string.h> #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)для Windows используйте '\ \ 'вместо'/'.
вот совет, если вы используете cmake. От: http://public.kitware.com/pipermail/cmake/2013-January/053117.html
я копирую подсказку, так что все это на этой странице:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")если вы используете GNU make, я не вижу причин, по которым вы не могли бы распространить это на свои собственные файлы makefiles. Например, у вас может быть такая строка:
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"здесь
$(SOURCE_PREFIX)- это префикс, который вы хотите удалить.затем использовать
__FILENAME__на месте__FILE__.
Я только что придумал отличное решение для этого, которое работает как с исходными, так и с заголовочными файлами, очень эффективно и работает во время компиляции на всех платформах без расширений, специфичных для компилятора. Это решение также сохраняет относительную структуру каталогов вашего проекта, поэтому вы знаете, в какой папке находится файл, и только относительно корня вашего проекта.
идея состоит в том, чтобы получить размер исходного каталога с помощью инструмента сборки и просто добавить его в
__FILE__макрос, полностью удаляя каталог и показывая только имя файла, начиная с исходного каталога.следующий пример реализован с использованием CMake, но нет причин, по которым он не будет работать с любыми другими инструментами сборки, потому что трюк очень прост.
на CMakeLists.txt файл, определите макрос, который имеет длину пути к вашему проекту на 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}")в исходном коде определите
__FILENAME__макрос, который просто добавляет источник размер пути к__FILE__макро:#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)тогда просто используйте этот новый макрос вместо
__FILE__макрос. Это работает, потому что__FILE__путь всегда будет начинаться с пути к вашему исходному каталогу CMake. Удалив его из__FILE__строка препроцессор позаботится о том, чтобы указать правильное имя файла, и все это будет относительно корня вашего проекта CMake.если вы заботитесь о производительности, это так эффективно, как использование
__FILE__, так как__FILE__иSOURCE_PATH_SIZEизвестны константы времени компиляции,поэтому он может быть оптимизирован компилятором.единственное место, где это не сработает,-это если вы используете это в сгенерированных файлах, и они находятся в папке сборки вне источника. Тогда вам, вероятно, придется создать еще один макрос с помощью
CMAKE_BUILD_DIRпеременной вместоCMAKE_SOURCE_DIR.
чисто время компиляции решение здесь. Это основано на том, что
sizeof()строкового литерала возвращает его длину+1.#define STRIPPATH(s)\ (sizeof(s) > 2 && (s)[sizeof(s)-2] == '/' ? (s) + sizeof(s) - 1 : \ sizeof(s) > 3 && (s)[sizeof(s)-3] == '/' ? (s) + sizeof(s) - 2 : \ sizeof(s) > 4 && (s)[sizeof(s)-4] == '/' ? (s) + sizeof(s) - 3 : \ sizeof(s) > 5 && (s)[sizeof(s)-5] == '/' ? (s) + sizeof(s) - 4 : \ sizeof(s) > 6 && (s)[sizeof(s)-6] == '/' ? (s) + sizeof(s) - 5 : \ sizeof(s) > 7 && (s)[sizeof(s)-7] == '/' ? (s) + sizeof(s) - 6 : \ sizeof(s) > 8 && (s)[sizeof(s)-8] == '/' ? (s) + sizeof(s) - 7 : \ sizeof(s) > 9 && (s)[sizeof(s)-9] == '/' ? (s) + sizeof(s) - 8 : \ sizeof(s) > 10 && (s)[sizeof(s)-10] == '/' ? (s) + sizeof(s) - 9 : \ sizeof(s) > 11 && (s)[sizeof(s)-11] == '/' ? (s) + sizeof(s) - 10 : (s)) #define __JUSTFILE__ STRIPPATH(__FILE__)Не стесняйтесь расширять каскад условных операторов до максимально разумного имени файла в проекте. Длина пути не имеет значения, если вы проверяете достаточно далеко от конца строки.
Я посмотрю, смогу ли я получить аналогичный макрос без жестко закодированной длины с рекурсией макросов...
по крайней мере для gcc, значение
__FILE__- путь к файлу как указано в командной строке компилятора. Если вы компилируетеfile.cтакой:gcc -c /full/path/to/file.cthe
__FILE__расширится до"/full/path/to/file.c". Если вы вместо этого:cd /full/path/to gcc -c file.cзатем
__FILE__расширится до просто"file.c".это может быть или не быть практичным.
стандарт C не требует такого поведения. Все это говорит о
__FILE__это то, что он расширяется до "Предполагаемое имя текущего исходного файла (символьный строковый литерал)".альтернативой является использование
там нет времени компиляции способ сделать это. Очевидно, что вы можете сделать это во время выполнения с помощью среды выполнения C, как показали некоторые другие ответы, но во время компиляции, когда запускается предварительный процесс, вам не повезло.
Так как вы используете GCC, вы можете воспользоваться на
__BASE_FILE__этот макрос расширяется до имени основного входного файла в виде Строковой константы C. Это исходный файл, который был указанный в командной строке препроцессора или компилятора Cа затем управлять тем, как вы хотите отобразить имя файла, изменив представление исходного файла (полный путь/относительный путь/базовое имя) во время компиляции.
использовать basename ()
небольшое изменение того, что @red1ynx предложил бы создать следующий макрос:
#define SET_THIS_FILE_NAME() \ static const char* const THIS_FILE_NAME = \ strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__;в каждом из ваших .c(ПП) файлы добавить:
SET_THIS_FILE_NAME();затем вы можете обратиться к
THIS_FILE_NAMEвместо__FILE__:printf("%s\n", THIS_FILE_NAME);Это означает, что строительство выполняется один раз за .файл c(pp) вместо каждого обращения к макросу.
он ограничен в использовании только .C (pp) файлы и были бы непригодны для использования из заголовочных файлов.
Я сделал макрос
__FILENAME__чтобы избежать резки полный путь каждый раз. Проблема заключается в том, чтобы сохранить имя результирующего файла в cpp-локальной переменной.это можно легко сделать, определив статическую глобальную переменную в .h. Это определение дает отдельные и независимые переменные в каждом .cpp файл, который включает в себя .h. Чтобы быть многопоточным, стоит сделать переменную (ы) также потоковой локальной (TLS).
один переменная хранит имя файла (сжатое). Другой содержит нерезанное значение, которое
__FILE__дал. Файл h:static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL; static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL;сам макрос вызывает метод со всей логикой:
#define __FILENAME__ \ GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName)и функция реализована таким образом:
const char* GetSourceFileName(const char* strFilePath, const char*& rstrFilePathHolder, const char*& 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; }removePath () может быть реализован по-разному, но быстрый и простой, кажется, с strrchr:
const char* removePath(const char* path) { const char* pDelimeter = strrchr (path, '\'); if (pDelimeter) path = pDelimeter+1; pDelimeter = strrchr (path, '/'); if (pDelimeter) path = pDelimeter+1; return path; }
просто надеюсь немного улучшить макрос файла:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\') ? strrchr(__FILE__, '\') + 1 : __FILE__)это ловит / и\, как просил царек Томчак, и это отлично работает в моей смешанной среде.
Если вы используете
CMAKEс компилятором GNU thisglobalопределить работает:set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")
попробовать
#pragma push_macro("__FILE__") #define __FILE__ "foobar.c"после включения операторов в исходный файл и добавить
#pragma pop_macro("__FILE__")в конце исходного файла.
в vs, когда с / FC, FILE равняется полный путь, без /FC FILE равным имени файла. ref здесь
вот решение, которое работает для сред, в которых нет библиотеки строк (ядро Linux, встроенные системы и т. д.):
#define FILENAME ({ \ const char* filename_start = __FILE__; \ const char* filename = filename_start; \ while(*filename != '') \ filename++; \ while((filename != filename_start) && (*(filename - 1) != '/')) \ filename--; \ filename; })Теперь просто используйте
FILENAMEвместо__FILENAME__. Да, это еще во время выполнения, но это работает.
вот портативная функция, которая работает как для Linux (путь '/'), так и для Windows (сочетание ' \ 'и'/').
компилируется с GCC, Clang и против#include <string.h> #include <stdio.h> const char* GetFileName(const char *path) { const char *name = NULL, *tmp = NULL; if (path && *path) { name = strrchr(path, '/'); tmp = strrchr(path, '\'); if (tmp) { return name && name > tmp ? name + 1 : tmp + 1; } } return name ? name + 1 : path; } int main() { const char *name = NULL, *path = NULL; path = __FILE__; name = GetFileName(path); printf("path: %s, filename: %s\n", path, name); path ="/tmp/device.log"; name = GetFileName(path); printf("path: %s, filename: %s\n", path, name); path = "C:\Downloads\crisis.avi"; name = GetFileName(path); printf("path: %s, filename: %s\n", path, name); path = "C:\Downloads/nda.pdf"; name = GetFileName(path); printf("path: %s, filename: %s\n", path, name); path = "C:/Downloads\word.doc"; name = GetFileName(path); printf("path: %s, filename: %s\n", path, name); path = NULL; name = GetFileName(NULL); printf("path: %s, filename: %s\n", path, name); path = ""; name = GetFileName(""); printf("path: %s, filename: %s\n", path, name); return 0; }стандартный вывод:
path: test.c, filename: test.c path: /tmp/device.log, filename: device.log path: C:\Downloads\crisis.avi, filename: crisis.avi path: C:\Downloads/nda.pdf, filename: nda.pdf path: C:/Downloads\word.doc, filename: word.doc path: (null), filename: (null) path: , filename:
вот решение, которое использует вычисление времени компиляции:
constexpr auto* getFileName(const char* const path) { const auto* startPosition = path; for (const auto* currentCharacter = path;*currentCharacter != ''; ++currentCharacter) { if (*currentCharacter == '\' || *currentCharacter == '/') { startPosition = currentCharacter; } } if (startPosition != path) { ++startPosition; } return startPosition; } std::cout << getFileName(__FILE__);
Comments