Makro pliku pokazuje pełną ścieżkę
Standardowe, predefiniowane makro__ FILE _ _ dostępne w języku C pokazuje pełną ścieżkę do pliku. Czy jest jakiś sposób na skrócenie ścieżki? Znaczy zamiast
/full/path/to/file.c
Widzę
to/file.c
Lub
file.c
17 answers
Try
#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
Dla Windows użyj '\ \ 'zamiast'/'.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-22 20:00:51
Oto wskazówka, jeśli używasz cmake. Od: http://public.kitware.com/pipermail/cmake/2013-January/053117.html
Kopiuję końcówkę więc wszystko jest na tej stronie:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
Jeśli używasz GNU make, nie widzę powodu, dla którego nie mógłbyś rozszerzyć tego na swoje własne pliki Makefile. Na przykład możesz mieć taką linię:
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"
Gdzie $(SOURCE_PREFIX)
jest przedrostkiem, który chcesz usunąć.
Następnie użyj __FILENAME__
zamiast __FILE__
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-20 21:40:20
Właśnie wymyśliłem świetne rozwiązanie, które działa zarówno z plikami źródłowymi, jak i nagłówkowymi, jest bardzo wydajne i działa w czasie kompilacji na wszystkich platformach bez rozszerzeń specyficznych dla kompilatora. To rozwiązanie zachowuje również względną strukturę katalogów projektu, dzięki czemu wiesz, w którym folderze znajduje się plik i tylko w stosunku do katalogu głównego projektu.
Chodzi o to, aby uzyskać rozmiar katalogu źródłowego za pomocą narzędzia do budowania i po prostu dodać go do makra __FILE__
, usunięcie katalogu całkowicie i pokazanie tylko nazwy pliku zaczynającej się w katalogu źródłowym.
Poniższy przykład jest zaimplementowany przy użyciu CMake, ale nie ma powodu, aby nie działał z innymi narzędziami do budowania, ponieważ sztuczka jest bardzo prosta.
Na Cmakelistach.plik txt, zdefiniuj makro, które ma długość ścieżki do twojego projektu na 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}")
W kodzie źródłowym zdefiniuj makro __FILENAME__
, które dodaje rozmiar ścieżki źródłowej do __FILE__
makro:
#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
Następnie po prostu użyj tego nowego makra zamiast makra __FILE__
. Działa to, ponieważ ścieżka __FILE__
będzie zawsze zaczynała się od ścieżki do katalogu źródłowego CMake. Usuwając go z łańcucha __FILE__
, preprocesor zadba o podanie poprawnej nazwy pliku i wszystko będzie względem katalogu głównego Twojego projektu CMake.
Jeśli zależy ci na wydajności, jest to równie efektywne jak użycie __FILE__
, ponieważ zarówno __FILE__
, jak i SOURCE_PATH_SIZE
są znanymi stałymi czasu kompilacji, więc może być zoptymalizowany przez kompilator.
Jedyne miejsce, gdzie to się nie powiedzie, to jeśli używasz tego na wygenerowanych plikach i są one w folderze kompilacji spoza źródła. Następnie prawdopodobnie będziesz musiał utworzyć kolejne makro używając zmiennej CMAKE_BUILD_DIR
zamiast CMAKE_SOURCE_DIR
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-20 20:06:06
Czysto skompilować rozwiązanie czasu tutaj. Opiera się na fakcie, że sizeof()
ciągu literalnego zwraca jego długość+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__)
Możesz rozszerzyć operator warunkowy do maksymalnej sensownej nazwy pliku w projekcie. Długość ścieżki nie ma znaczenia, o ile sprawdzasz wystarczająco daleko od końca łańcucha.
Zobaczę, czy uda mi się uzyskać podobne makro bez zakodowanej długości z rekurencją makra...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-02 17:24:33
Przynajmniej dla gcc, wartość __FILE__
jest ścieżką pliku określoną w wierszu poleceń kompilatora. Jeśli skompilujesz file.c
w ten sposób:
gcc -c /full/path/to/file.c
__FILE__
rozszerzy się do "/full/path/to/file.c"
. Jeśli zamiast tego zrobisz to:
cd /full/path/to
gcc -c file.c
Następnie __FILE__
rozszerzy się do tylko "file.c"
.
To może, ale nie musi być praktyczne.
Standard C nie wymaga takiego zachowania. Wszystko, co mówi o __FILE__
, to to, że rozszerza się do " domniemanej nazwy bieżącego pliku źródłowego (znaku string literal)".
Alternatywą jest użycie dyrektywy #line
. Nadpisuje bieżący numer linii i opcjonalnie nazwę pliku źródłowego. Jeśli chcesz nadpisać nazwę pliku, ale pozostawić tylko numer linii, użyj makra __LINE__
.
Na przykład, możesz dodać to w pobliżu góry file.c
:
#line __LINE__ "file.c"
Upewnienie się, że nazwa pliku w dyrektywie #line
odpowiada rzeczywistej nazwie pliku jest pozostawione jako ćwiczenie.
Przynajmniej dla gcc, będzie to miało również wpływ nazwa pliku zgłaszana w komunikatach diagnostycznych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-10 18:44:58
Nie ma na to czasu kompilacji. Oczywiście możesz to zrobić w trybie runtime używając C runtime, jak wykazały niektóre inne odpowiedzi, ale w czasie kompilacji, kiedy Pre-procesor uruchamia się, masz pecha.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 11:29:32
Ponieważ używasz GCC, Możesz wykorzystać z
__BASE_FILE__
makro to rozszerza się do nazwy głównego pliku wejściowego w postaci stałej ciągu C. Jest to plik źródłowy, który został określone w wierszu poleceń preprocesora lub kompilatora C
A następnie kontroluj sposób wyświetlania nazwy pliku, zmieniając reprezentację pliku źródłowego (pełna ścieżka/względna ścieżka/nazwa Podstawowa) w czasie kompilacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 11:44:21
Użyj funkcji basename () lub, jeśli używasz systemu Windows, _splitpath () .
#include <libgen.h>
#define PRINTFILE() { char buf[] = __FILE__; printf("Filename: %s\n", basename(buf)); }
Spróbuj również man 3 basename
w powłoce.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 11:54:33
Mała różnica w tym, co @ red1ynx zaproponował, aby utworzyć następujące makro:
#define SET_THIS_FILE_NAME() \
static const char* const THIS_FILE_NAME = \
strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__;
W każdym z was .pliki c (pp) dodaj:
SET_THIS_FILE_NAME();
Wtedy możesz odnieść się do THIS_FILE_NAME
zamiast __FILE__
:
printf("%s\n", THIS_FILE_NAME);
Oznacza to, że konstrukcja jest wykonywana raz na .plik C (pp) zamiast za każdym razem, gdy makro jest odwołane.
Jest ograniczony do stosowania tylko z .pliki C (pp) i byłyby bezużyteczne z plików nagłówkowych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 11:39:58
Zrobiłem makro __FILENAME__
, które pozwala uniknąć cięcia pełnej ścieżki za każdym razem. Problem polega na trzymaniu wynikowej nazwy pliku w zmiennej lokalnej cpp.
Można to łatwo zrobić definiując statyczną zmienną globalną w .h Plik. Definicja ta daje oddzielne i niezależne zmienne w każdym .plik cpp zawierający .h . Aby być odpornym na wielowątkowość warto uczynić zmienną (- ami) również thread local (TLS).
Jedna zmienna przechowuje nazwę pliku (skurczył). Inny posiada wartość non-cut, którą __FILE__
dał. Plik h:
static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL;
static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL;
Samo makro wywołuje metodę z całą logiką:
#define __FILENAME__ \
GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName)
I funkcja jest zaimplementowana w ten sposób:
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 () może być zaimplementowane na różne sposoby, ale szybkie i proste wydaje się być za pomocą 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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-18 14:49:46
Po prostu mam nadzieję poprawić trochę makro pliku:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
To łapie / i\, jak prosił Czarek Tomczak, a to świetnie sprawdza się w moim mieszanym środowisku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-06 13:49:42
Jeśli używasz CMAKE
z kompilatorem GNU to global
define działa dobrze:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-28 11:09:50
Try
#pragma push_macro("__FILE__")
#define __FILE__ "foobar.c"
Po poleceniach include w pliku źródłowym i dodaj
#pragma pop_macro("__FILE__")
Na końcu pliku źródłowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-12 09:42:57
W vs, gdy z /FC, Plik jest równy pełnej ścieżce, bez /FC Plik jest równy nazwie pliku. ref tutaj
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 05:33:05
Oto rozwiązanie, które działa w środowiskach, które nie mają biblioteki string (jądro Linuksa, systemy wbudowane itp.):
#define FILENAME ({ \
const char* filename_start = __FILE__; \
const char* filename = filename_start; \
while(*filename != '\0') \
filename++; \
while((filename != filename_start) && (*(filename - 1) != '/')) \
filename--; \
filename; })
Teraz po prostu użyj FILENAME
zamiast __FILENAME__
. Tak, to nadal jest runtime, ale działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 19:41:18
Oto przenośna funkcja, która działa zarówno dla Linuksa (ścieżka'/'), jak i Dla Windows (połączenie '\' i '/').
kompiluje z gcc, clang i Vs.
#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;
}
Standardowe wyjście:
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:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-13 13:27:54
Oto rozwiązanie, które wykorzystuje obliczenia czasu kompilacji:
constexpr auto* getFileName(const char* const path)
{
const auto* startPosition = path;
for (const auto* currentCharacter = path;*currentCharacter != '\0'; ++currentCharacter)
{
if (*currentCharacter == '\\' || *currentCharacter == '/')
{
startPosition = currentCharacter;
}
}
if (startPosition != path)
{
++startPosition;
}
return startPosition;
}
std::cout << getFileName(__FILE__);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 16:17:17