2009-07-10 3 views
5

다음 코드를 고려C++ 함수 호출 식별자

void Foo() { 
    ...... 
    LOG_ERROR("I'm error 1") // call 1 
    ..... 
    LOG_ERROR("I'm error 2") // call 2 
    ..... 

} 

LOG_ERROR() 매크로이다. LOG_ERROR()은 코드를 식별하는 문자열을 인쇄해야하지만 코드는 변경 될 수 있지만 A::Foo() 은 변경되지 않습니다. 코드 이 변경되는 동안 식별자는 유지되어야합니다.

LOG_ERROR(), 에 인수로 추가 오류 코드에 의해 해결 될 수 있지만, 우리는 오류를 코드를 관리하는 부담 프로그래머에서 제거하려는.

__LINE__을 사용하면 Foo()이 (가) 빌드로 이동할 수 있기 때문에 답변이 아닙니다.

그러므로 나는 Foo() 시작으로 LOG_ERROR() 상대를 식별 생각 :

  • 을 수행합니다. 파일 이름 (__FILE__) + 함수 이름 (__FUNCTION__) + LOG_ERROR()의 줄 번호를 Foo() 시작과 비교하여 식별하십시오.
  • b. 파일 이름 (__FILE__) + 함수 이름 (__FUNCTION__) + LOG_ERROR()의 호출 번호는 Foo()입니다.

해결책은 최소한 VC++ 2008 및 g ++ 4.1.1에서 작동해야합니다.

한 제안 된 솔루션 (link text)입니다 :

#define ENABLE_LOG_ERROR static const int LOG_ERROR_start_line = __LINE__ 
#define LOG_ERROR(s) cerr << "error #" << (__LINE__ - LOG_ERROR_start_line) \ 
    << " in " << __func__ << ": " << s << endl 

void Foo() { 
    ENABLE_LOG_ERROR; 
    //... 
    LOG_ERROR("error 1"); 
    int i; 
    LOG_ERROR("error 2"); 
} 

LOG_ERROR() 많은 같은 기능이있어 포함하는 각 기능의 시작에 ENABLE_LOG_ERROR를 작성하는 사용자를 강제로.

다른 방법으로 작업을 수행 할 수 있습니까?

+0

@idimba 너무 많은 문제가 없다면 스크립트를 사용하여 모든 함수 이름 바로 뒤에 자동으로 'ENABLE_LOG_ERROR;'를 추가 할 수 있습니다. 그 트릭을 * 타사 코드를 탐색 할 때 사용합니다. –

+0

좋은 생각이지만, 우리가 로깅 서브 서멀에서 광범위하게 사용하는 __LINE__에 영향을 줄 것입니다. – dimba

답변

0

스택 아이디어를 수정하여 std::string에서 매핑하는 std::map을 사용하고 함수 이름을 조회합니다.

std::map<std::string, int> LOG_ERROR_count_map; 
#define LOG_ERROR(s) {\ 
    int count = ++LOG_ERROR_count_map[ __func__ ];\ 
    std::cout << count << " in " __func__ ": " s << std::endl;\ 
} 

이것은 당신이 ENABLE_LOG_ERROR이 필요하지만, 각 로그에 대한지도 룩업의 비용으로하지 않는 것을 의미한다.

+0

내 솔루션과 GMan 모두 함수에서 LOG_ERROR의 n 번째 인스턴스를 제공하지 않지만 함수에서 LOG_ERROR의 n 번째 호출은 제공하지 않습니다. 따라서 분기가 발생할 때 용도 (아마도 의도 된 용도)를 카운트 다운하는 데 사용할 수 없습니다. 동적 계산 방법의 어떤 형태도 작동하지 않습니다. –

+0

아마도 분명하지만, 함수 이름이 변경되었을 때이를 감지 할 수있는 방법이 없기 때문에 함수 이름을 기반으로하는 정적 카운트에 대해 전 처리기를 사용할 수 없다는 점을 지적 할 가치가 있습니다. 문자열을 비교할 수 없습니다. –

1

이 솔루션은 비표준입니다 (이. 사용 편의성과 시간 사이의 트레이드 오프입니다)하지만, MSVC하고 호출 할 때마다 증가 GCC 지원 __COUNTER__, 모두. __COUNTER__ 각 컴파일 단위에서 리셋하고, 각 컴파일 단위에있을 것

#define LOG_ERROR(s) cerr << "error #" << (__COUNTER__) << " in " \ 
<< __func__ << ": " << s << endl 

참고. 따라서 Foo()에 매크로가인 경우 나중에 함수 Bar()__COUNTER__의 값은 처음 사용시 LOG_ERROR() 일 때 7이됩니다.

+0

그러나 이것은 함수 사이에서 작동하지 않습니다. – GManNickG

+0

실제 문제는 새 메시지를 삽입하면 그 아래 메시지의 번호가 모두 다시 매겨집니다. –

+0

@GMan : 각 기능에 대해 재설정되지 않는다는 것이 맞습니다. 나는 그것을 명확히하기 위해 편집했습니다. @ 귀갑개 : 또한 정확합니다. 이것은 상당히 부서지기 쉬운 해결책입니다. 'LOG_ERROR()'는 같은 컴파일 유닛의 모든 이전 호출 이후에만 추가된다고 가정합니다. – Geerad

1

문제는 로깅 목적을위한 함수 내에서 고유 한 라인 식별자를 생성하는 방법에 관한 것이지만 실제 문제를 해결하기 위해 살펴볼 것입니다. 쉽게 식별 할 수있는 로그 출력을 생성하는 방법 코드의 작성자에게 부담을주지 않으면 서 소스 코드 라인.

프로그램의 각 릴리스마다 고유 한 빌드 버전을 포함한다고 가정합니다 (일반적으로 좋은 아이디어입니다). 또한 소스 코드의 히스토리를 유지하는 소스 코드 제어 메커니즘을 사용하고 있다고 가정합니다 (어쨌든 매우 좋은 아이디어입니다). 그리고 요청 된 빌드 버전의 소스를 소스로 제공 할 수 있습니다. 프로그램.

이러한 가정이 사실이라면 솔루션은 프로그램에 현재 버전을 로그 파일에 기록하도록하는 것입니다. 그런 다음 각 개별 로깅 항목은 단순히 __LINE__을 통해 회선 번호를 기록 할 수 있습니다.

따라서 누군가 로그를 사용해야 할 때 : 로그의 버전 번호를보고 소스 코드 제어 저장소에서 해당 소스를 가져온 다음 로그의 행 번호를 사용하여 적절한 소스로 이동할 수 있습니다 윤곽. 이것은 로그 출력을 사용하는 사람에게 약간의 부담을줍니다. 그러나 로그 된 코드가 버전마다 다를 수있는 다른 코드에 종속되거나 영향을받는 경우 소스 코드의 이전 상태가 필요합니다.

또한이 방법으로 작업하면 얻을 수있는 이점 중 하나는 질문의 원래 일부였던 것처럼 주어진 함수가 변경되지 않는다고 가정해야한다는 것입니다. 따라서이 방법은 훨씬 더 광범위하게 적용됩니다.


프로그램이 시작될 때 프로그램 버전을 기록하거나 각 항목에 로깅 매크로를 포함시킬 수 있습니다.

보통 소스 코드에서 프로그램 버전이 쉽게 액세스 할 수없는 곳에 저장되어있는 경우 버전을 추출하여 #define 또는 const로 간단한 version.h 파일에 작성하는 사전 빌드 단계를 만들 수 있습니다 끈. 그런 다음 로깅 코드 또는 매크로가 자동으로이를 사용하여 항상 현재 버전의 프로그램을 출력 할 수 있습니다.