[c] __FILE__ macro shows full path

The standard predefined macro __FILE__ available in C shows the full path to the file. Is there any way to short the path? I mean instead of

/full/path/to/file.c

I see

to/file.c

or

file.c

This question is related to c file macros path

The answer is


A slight variation on what @red1ynx proposed would to be create the following macro:

#define SET_THIS_FILE_NAME() \
    static const char* const THIS_FILE_NAME = \
        strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__;

In each of your .c(pp) files add:

SET_THIS_FILE_NAME();

Then you can refer to THIS_FILE_NAME instead of __FILE__:

printf("%s\n", THIS_FILE_NAME);

This means the construction is performed once per .c(pp) file instead of each time the macro is referenced.

It is limited to use only from .c(pp) files and would be unusable from header files.


If you are using CMAKE with GNU compiler this global define works fine:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")

A tweaked, even more "bloated" version of red1ynx's answer:

#define __FILENAME__ \
  (strchr(__FILE__, '\\') \
  ? ((strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)) \
  : ((strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)))

If we find backslashes, we split on backslashes. Otherwise, split on forward slash. Simple enough.

Just about any alternative would be cleaner (A C++ constexpr is really the gold standard here, in my opinion). However, this may be helpful if you're using some compiler where __BASE_FILE__ isn't available.


At least for gcc, the value of __FILE__ is the file path as specified on the compiler's command line. If you compile file.c like this:

gcc -c /full/path/to/file.c

the __FILE__ will expand to "/full/path/to/file.c". If you instead do this:

cd /full/path/to
gcc -c file.c

then __FILE__ will expand to just "file.c".

This may or may not be practical.

The C standard does not require this behavior. All it says about __FILE__ is that it expands to "The presumed name of the current source ?le (a character string literal)".

An alternative is to use the #line directive. It overrides the current line number, and optionally the source file name. If you want to override the file name but leave the line number alone, use the __LINE__ macro.

For example, you can add this near the top of file.c:

#line __LINE__ "file.c"

The only problem with this is that it assigns the specified line number to the following line, and the first argument to #line has to be a digit-sequence so you can't do something like

#line (__LINE__-1) "file.c"  // This is invalid

Ensuring that the file name in the #line directive matches the actual name of the file is left as an exercise.

At least for gcc, this will also affect the file name reported in diagnostic messages.


I have use the same solution with @Patrick 's answer for years.

It has a small issue when the full path contains symbol-link.

Better solution.

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")

Why should use this ?

  • -Wno-builtin-macro-redefined to mute the compiler warnings for redefining __FILE__ macro.

    For those compilers do not support this, refer to the Robust way below.

  • Strip the project path from the file path is your real requirement. You won't like to waste the time to find out where is a header.h file, src/foo/header.h or src/bar/header.h.

  • We should strip the __FILE__ macro in cmake config file.

    This macro is used in most exists codes. Simply redefine it can set you free.

    Compilers like gcc predefines this macro from the command line arguments. And the full path is written in makefiles generated by cmake.

  • Hard code in CMAKE_*_FLAGS is required.

    There is some commands to add compiler options or definitions in some more recently version, like add_definitions() and add_compile_definitions(). These commands will parse the make functions like subst before apply to source files. That is not we want.

Robust way for -Wno-builtin-macro-redefined.

include(CheckCCompilerFlag)
check_c_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)

Remember to remove this compiler option from the set(*_FLAGS ... -D__FILE__=...) line.


Since you are using GCC, you can take advantage of

__BASE_FILE__ This macro expands to the name of the main input file, in the form of a C string constant. This is the source file that was specified on the command line of the preprocessor or C compiler

and then control how you want to display the filename by changing the source file representation (full path/relative path/basename) at compilation time.


I did a macro __FILENAME__ that avoids cutting full path each time. The issue is to hold the resulting file name in a cpp-local variable.

It can be easily done by defining a static global variable in .h file. This definition gives separate and independent variables in each .cpp file that includes the .h. In order to be a multithreading-proof it worth to make the variable(s) also thread local (TLS).

One variable stores the File Name (shrunk). Another holds the non-cut value that __FILE__ gave. The h file:

static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL;
static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL;

The macro itself calls method with all the logic:

#define __FILENAME__ \
    GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName)

And the function is implemented this way:

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;
}

The removePath() can be implemented in different ways, but the fast and simple seems to be with 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;
}

Here is the solution that uses compile-time calculation:

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__);

Here's a solution that works for environments that don't have the string library (Linux kernel, embedded systems, etc):

#define FILENAME ({ \
    const char* filename_start = __FILE__; \
    const char* filename = filename_start; \
    while(*filename != '\0') \
        filename++; \
    while((filename != filename_start) && (*(filename - 1) != '/')) \
        filename--; \
    filename; })

Now just use FILENAME instead of __FILENAME__. Yes, it's still a runtime thing but it works.


If you ended up on this page looking for a way to remove absolute source path that is pointing to ugly build location from the binary that you are shipping, below might suit your needs.

Although this doesn't produce exactly the answer that the author has expressed his wish for since it assumes the use of CMake, it gets pretty close. It's a pity this wasn't mentioned earlier by anyone as it would have saved me loads of time.

OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)

Setting above variable to ON will generate build command in the format:

cd /ugly/absolute/path/to/project/build/src && 
    gcc <.. other flags ..> -c ../../src/path/to/source.c

As a result, __FILE__ macro will resolve to ../../src/path/to/source.c

CMake documentation

Beware of the warning on the documentation page though:

Use relative paths (May not work!).

It is not guaranteed to work in all cases, but worked in mine - CMake 3.13 + gcc 4.5


  • C++11
  • msvc2015u3,gcc5.4,clang3.8.0

    template <typename T, size_t S>
    inline constexpr size_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>
    inline constexpr size_t get_file_name_offset(T (& str)[1])
    {
        return 0;
    }
    

    '

    int main()
    {
         printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
    }
    

Code generates a compile time offset when:

  • gcc: at least gcc6.1 + -O1
  • msvc: put result into constexpr variable:

      constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
      printf("%s\n", file);
    
  • clang: persists on not compile time evaluation

There is a trick to force all 3 compilers does compile time evaluation even in the debug configuration with disabled optimization:

    namespace utility {

        template <typename T, T v>
        struct const_expr_value
        {
            static constexpr const 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__))]);
    }

https://godbolt.org/z/u6s8j3


Use the basename() function, or, if you are on Windows, _splitpath().

#include <libgen.h>

#define PRINTFILE() { char buf[] = __FILE__; printf("Filename:  %s\n", basename(buf)); }

Also try man 3 basename in a shell.


I have just thought of a great solution to this that works with both source and header files, is very efficient and works on compile time in all platforms without compiler-specific extensions. This solution also preserves the relative directory structure of your project, so you know in which folder the file is in, and only relative to the root of your project.

The idea is to get the size of the source directory with your build tool and just add it to the __FILE__ macro, removing the directory entirely and only showing the file name starting at your source directory.

The following example is implemented using CMake, but there's no reason it wouldn't work with any other build tools, because the trick is very simple.

On the CMakeLists.txt file, define a macro that has the length of the path to your project on 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}")

On your source code, define a __FILENAME__ macro that just adds the source path size to the __FILE__ macro:

#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)

Then just use this new macro instead of the __FILE__ macro. This works because the __FILE__ path will always start with the path to your CMake source dir. By removing it from the __FILE__ string the preprocessor will take care of specifying the correct file name and it will all be relative to the root of your CMake project.

If you care about the performance, this is as efficient as using __FILE__, because both __FILE__ and SOURCE_PATH_SIZE are known compile time constants, so it can be optimized away by the compiler.

The only place where this would fail is if you're using this on generated files and they're on a off-source build folder. Then you'll probably have to create another macro using the CMAKE_BUILD_DIR variable instead of CMAKE_SOURCE_DIR.


There's no compile time way to do this. Obviously you can do it at runtime using the C runtime, as some of the other answers have demonstrated, but at compile time, when the pre-procesor kicks in, you're out of luck.


Here is a portable function that works for both Linux (path '/') and Windows (mix of '\' and '/').
Compiles with gcc, clang and 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;
}

Standard output:

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: 

just hope to improve FILE macro a bit:

#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

this catches / and \, like Czarek Tomczak requested, and this works great in my mixed environment.


Here's a tip if you're using cmake. From: http://public.kitware.com/pipermail/cmake/2013-January/053117.html

I'm copying the tip so it's all on this page:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
  ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")

If you're using GNU make, I see no reason you couldn't extend this to your own makefiles. For example, you might have a line like this:

CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"

where $(SOURCE_PREFIX) is the prefix that you want to remove.

Then use __FILENAME__ in place of __FILE__.


Purely compile time solution here. It's based on the fact that sizeof() of a string literal returns its length+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__)

Feel free to extend the conditional operator cascade to the maximum sensible file name in the project. Path length doesn't matter, as long as you check far enough from the end of the string.

I'll see if I can get a similar macro with no hard-coded length with macro recursion...


Try

#pragma push_macro("__FILE__")
#define __FILE__ "foobar.c"

after the include statements in your source file and add

#pragma pop_macro("__FILE__")

at the end of your source file.


#include <algorithm>
#include <string>
using namespace 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

GCC 8 now has the -fmacro-prefix-map and -ffile-prefix-map options:

-fmacro-prefix-map=old=new

When preprocessing files residing in directory old, expand the __FILE__ and __BASE_FILE__ macros as if the files resided in directory new instead. This can be used to change an absolute path to a relative path by using . for new which can result in more reproducible builds that are location independent. This option also affects __builtin_FILE() during compilation. See also -ffile-prefix-map.

-ffile-prefix-map=old=new

When compiling files residing in directory old, record any references to them in the result of the compilation as if the files resided in directory new instead. Specifying this option is equivalent to specifying all the individual -f*-prefix-map options. This can be used to make reproducible builds that are location independent. See also -fmacro-prefix-map and -fdebug-prefix-map.

Setting an invalid path for -ffile-prefix-map (-fdebug-prefix-map) will break debugging unless you tell your debugger how to map back. (gdb: set substitue-path, vscode: "sourceFileMap").

If your intent is to only clean up __FILE__ just use -fmacro-prefix-map.

Example: So for my Jenkins builds I will add -ffile-prefix-map=${WORKSPACE}/=/, and another to remove the local dev package install prefix.

NOTE Unfortunately the -ffile-prefix-map and -fmacro-prefix-map options are only available in GCC 8 onwards. For, say, GCC 5, we only have -fdebug-prefix-map which does not affect __FILE__.


Recent Clang compiler has a __FILE_NAME__ macro (see here).


A short, working answer for both Windows and *nix:

#define __FILENAME__ std::max<const char*>(__FILE__,\
    std::max(strrchr(__FILE__, '\\')+1, strrchr(__FILE__, '/')+1))

In VC, when using /FC, __FILE__ expands to the full path, without the /FC option __FILE__ expands file name. ref: here


Examples related to c

conflicting types for 'outchar' Can't compile C program on a Mac after upgrade to Mojave Program to find largest and second largest number in array Prime numbers between 1 to 100 in C Programming Language In c, in bool, true == 1 and false == 0? How I can print to stderr in C? Visual Studio Code includePath "error: assignment to expression with array type error" when I assign a struct field (C) Compiling an application for use in highly radioactive environments How can you print multiple variables inside a string using printf?

Examples related to file

Gradle - Move a folder from ABC to XYZ Difference between opening a file in binary vs text Angular: How to download a file from HttpClient? Python error message io.UnsupportedOperation: not readable java.io.FileNotFoundException: class path resource cannot be opened because it does not exist Writing JSON object to a JSON file with fs.writeFileSync How to read/write files in .Net Core? How to write to a CSV line by line? Writing a dictionary to a text file? What are the pros and cons of parquet format compared to other formats?

Examples related to macros

How to use __DATE__ and __TIME__ predefined macros in as two integers, then stringify? how to use #ifdef with an OR condition? What is ":-!!" in C code? How to pass macro definition from "make" command line arguments (-D) to C source code? __FILE__ macro shows full path Where are the recorded macros stored in Notepad++? How to identify platform/compiler from preprocessor macros? What does "#pragma comment" mean? C Macro definition to determine big endian or little endian machine? How do I show the value of a #define at compile-time?

Examples related to path

Get Path from another app (WhatsApp) How to serve up images in Angular2? How to create multiple output paths in Webpack config Setting the correct PATH for Eclipse How to change the Jupyter start-up folder Setting up enviromental variables in Windows 10 to use java and javac How do I edit $PATH (.bash_profile) on OSX? Can't find SDK folder inside Android studio path, and SDK manager not opening Get the directory from a file path in java (android) Graphviz's executables are not found (Python 3.4)