[c] __FILE__ 매크로는 전체 경로를 보여줍니다

__FILE__C에서 사용 가능한 표준 사전 정의 매크로 는 파일의 전체 경로를 보여줍니다. 경로를 단축 할 수있는 방법이 있습니까? 대신에

/full/path/to/file.c

내가 참조

to/file.c

또는

file.c



답변

시험

#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를 사용한다면, 이것을 자신의 makefile로 확장 할 수 없었습니다. 예를 들어 다음과 같은 줄이있을 수 있습니다.

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.c

__FILE__확장됩니다 "/full/path/to/file.c". 대신 이렇게하면 :

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

다음으로 __FILE__확장됩니다 "file.c".

이것은 실용적 일 수도 있고 아닐 수도 있습니다.

C 표준에는이 동작이 필요하지 않습니다. 그것에 대해 말한다 모두 __FILE__는 “현재 소스 Fi를 르 (문자열 리터럴)의 추정 이름”으로 확장한다는 것이다.

대안은 #line지시문 을 사용하는 것 입니다. 현재 행 번호 및 선택적으로 소스 파일 이름을 대체합니다. 파일 이름을 무시하고 줄 번호 만 남겨 두려면 __LINE__매크로를 사용하십시오 .

예를 들어, 맨 위에 다음을 추가 할 수 있습니다 file.c.

#line __LINE__ "file.c"

이것에 대한 유일한 문제는 지정된 줄 번호를 다음 줄에 할당하고 첫 번째 인수 #line숫자 시퀀스 여야 하므로 다음과 같은 작업을 수행 할 수 없다는 것입니다

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

#line지시문 의 파일 이름이 파일 의 실제 이름과 일치 하는지 확인하는 것은 연습으로 남습니다.

최소한 gcc의 경우 진단 메시지에보고 된 파일 이름에도 영향을 미칩니다.


답변

파티에 약간 늦었지만 GCC의 경우 -ffile-prefix-map=old=new옵션을 살펴보십시오 .

old 디렉토리에있는 파일을 컴파일 할 때 , 파일이 new 디렉토리에있는 것처럼 컴파일 결과에 대한 참조를 기록하십시오 . 이 옵션을 지정하는 것은 모든 개별 -f*-prefix-map옵션 을 지정하는 것과 같습니다 . 위치에 독립적 인 재현 가능한 빌드를 만드는 데 사용할 수 있습니다. 참조
-fmacro-prefix-map-fdebug-prefix-map.

따라서 Jenkins 빌드의 -ffile-prefix-map=${WORKSPACE}/=/경우 로컬 개발자 패키지 설치 접두사를 제거하기 위해를 추가 하고 다른 것을 추가 합니다.

참고 불행히도 -ffile-prefix-map옵션은, 이후 GCC 8 만 avalable입니다 -fmacro-prefix-map, 이는 내 생각 은 않는 __FILE__부분. 예를 들어 GCC 5에 대해서는 -fdebug-prefix-map영향을 미치지 않는 것만 나타납니다 __FILE__.


답변

  • 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__)]);
    }

다음과 같은 경우 코드에서 컴파일 시간 오프셋을 생성합니다.

  • gcc: 적어도 gcc6.1 + -O1
  • msvc: constexpr 변수에 결과를 넣습니다.

      constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
      printf("%s\n", file);
  • clang: 컴파일 시간 평가를하지 않으면 지속

최적화를 비활성화 한 디버그 구성에서도 3 개의 컴파일러가 모두 컴파일 시간 평가를 수행하도록하는 트릭이 있습니다.

    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