디버깅 목적으로 C / C ++ 컴파일러 에서 줄 번호를 얻을 수 있습니까? (특정 컴파일러에 대한 표준 방식 또는 특정 방식)
예 :
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
디버깅 목적으로 C / C ++ 컴파일러 에서 줄 번호를 얻을 수 있습니까? (특정 컴파일러에 대한 표준 방식 또는 특정 방식)
예 :
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
답변:
전 처리기 매크로 __LINE__
와 __FILE__
. 미리 정의 된 매크로이며 C / C ++ 표준의 일부입니다. 전처리 중에 현재 행 번호와 현재 파일 이름을 나타내는 정수가 들어있는 상수 문자열로 각각 대체됩니다.
기타 전 처리기 변수 :
__func__
: 함수 이름 (이것은 C99의 일부이며 모든 C ++ 컴파일러가 지원하는 것은 아닙니다)__DATE__
: "Mmm dd yyyy"형식의 문자열__TIME__
: "hh : mm : ss"형식의 문자열코드는 다음과 같습니다.
if(!Logical)
printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);
#define S1(N) #N
#define S2(N) S1(N)
#define LINESTR S2(__LINE__)
. c-faq.com/ansi/stringize.html
__func__
은 매크로가 아니라 암시 적으로 선언 된 변수입니다.
C ++ 표준의 일부로 사용할 수있는 사전 정의 된 매크로가 있습니다. C ++ 표준의 섹션 16.8은 무엇보다도 __LINE__
매크로를 정의합니다 .
__LINE__
: 현재 소스 라인의 라인 번호 (10 진수 상수).
__FILE__
: 소스 파일의 추정 이름 (문자열 리터럴).
__DATE__
: 소스 파일 번역 일 (문자열 리터럴 ...)
__TIME__
: 소스 파일 번역 시간 (문자열 리터럴 ...)
__STDC__
:__STDC__
사전 정의 여부
__cplusplus
: 이름__cplusplus
은 199711L 값으로 정의됩니다. C ++ 번역 단위 컴파일
따라서 코드는 다음과 같습니다.
if(!Logical)
printf("Not logical value at line number %d \n",__LINE__);
함수 이름, 클래스 및 줄 번호와 같은 디버그 정보도 포함한다는 점을 제외하면 printf () 와 동일한 동작으로 매크로를 사용할 수 있습니다 .
#include <cstdio> //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a, __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)
이러한 매크로는 java stacktrace와 같은 정보를 포함하면서 printf () 와 동일하게 작동해야합니다 . 다음은 메인의 예입니다.
void exampleMethod() {
println("printf() syntax: string = %s, int = %d", "foobar", 42);
}
int main(int argc, char** argv) {
print("Before exampleMethod()...\n");
exampleMethod();
println("Success!");
}
결과는 다음과 같습니다.
main (main.cpp : 11) 이전 exampleMethod () ...
exampleMethod (main.cpp : 7) printf () 구문 : string = foobar, int = 42
main (main.cpp : 13) 성공했습니다!
#include
에<stdio.h>
C ++ 20은 std :: source_location 을 사용하여이를 달성하는 새로운 방법을 제공합니다 . 이것은 현재 gcc 및 clang std::experimental::source_location
에서 #include <experimental/source_location>
.
같은 매크로의 문제 __LINE__
는 메시지와 함께 현재 행 번호를 출력하는 로깅 함수를 생성하려는 경우 __LINE__
호출 사이트에서 확장되기 때문에 항상 함수 인수 로 전달해야한다는 것입니다. 이 같은:
void log(const std::string msg) {
std::cout << __LINE__ << " " << msg << std::endl;
}
log
실제로 호출 된 행이 아니라 항상 함수 선언 행을 출력합니다 . 반면에 std::source_location
다음과 같이 작성할 수 있습니다.
#include <experimental/source_location>
using std::experimental::source_location;
void log(const std::string msg, const source_location loc = source_location::current())
{
std::cout << loc.line() << " " << msg << std::endl;
}
여기서는 호출 된 loc
위치를 가리키는 줄 번호로 초기화됩니다 log
.
여기에서 온라인으로 시도 할 수 있습니다.
시도 __FILE__
하고 __LINE__
.
또한 찾을 수 __DATE__
있고 __TIME__
유용 할 수 있습니다 .
클라이언트 측에서 프로그램을 디버깅해야하므로 이러한 정보를 기록해야하는 경우가 아니면 일반 디버깅을 사용해야합니다.
raw code
(예 :`__`). @mmyers는 도움을 주려고했지만 밑줄 중 하나만 이스케이프 처리했기 때문에 이탤릭체에 대한 마크 업 구문이 남았습니다 . 그러나 여기에서 반대표는 약간 가혹하지만 동의합니다.
나는 또한 지금이 문제에 직면하고 있고 여기 에서 묻는 다른 유효한 질문에 대한 답변을 추가 할 수 없기 때문에 문제에 대한 예제 솔루션을 제공 할 것입니다 : 함수가 호출 된 줄 번호 만 가져 오기 템플릿을 사용하는 C ++.
배경 : C ++에서는 형식이 아닌 정수 값을 템플릿 인수로 사용할 수 있습니다. 이것은 템플릿 인수로 데이터 유형의 일반적인 사용과 다릅니다. 따라서 아이디어는 함수 호출에 이러한 정수 값을 사용하는 것입니다.
#include <iostream>
class Test{
public:
template<unsigned int L>
int test(){
std::cout << "the function has been called at line number: " << L << std::endl;
return 0;
}
int test(){ return this->test<0>(); }
};
int main(int argc, char **argv){
Test t;
t.test();
t.test<__LINE__>();
return 0;
}
산출:
이 함수는 줄 번호 : 0에서 호출되었습니다.
이 함수는 줄 번호 : 16에서 호출되었습니다.
여기서 언급해야 할 한 가지는 C ++ 11 Standard에서는 템플릿을 사용하여 함수에 대한 기본 템플릿 값을 제공 할 수 있다는 것입니다. C ++ 11 이전 버전에서는 형식이 아닌 인수에 대한 기본값이 클래스 템플릿 인수에 대해서만 작동하는 것 같습니다. 따라서 C ++ 11에서는 위와 같이 중복 된 함수 정의를 가질 필요가 없습니다. C ++ 11에서 그와 같은 리터럴 함께 사용하는 const를 문자 * 템플릿 인수하지만 가능하지 않은 것이 또한 유효 __FILE__
또는 __func__
언급 한 바와 같이 여기를 .
따라서 결국 C ++ 또는 C ++ 11을 사용하는 경우 매크로를 사용하여 호출 라인을 얻는 것보다 매우 흥미로운 대안이 될 수 있습니다.
을 사용 __LINE__
하지만 그 유형은 무엇입니까?
LINE 현재 소스 행 (정수 상수)의 추정 행 번호 (현재 소스 파일 내).
AS를 정수 상수 , 코드는 종종 값이 가정 할 수 __LINE__ <= INT_MAX
와 종류가 그래서 int
.
C로 인쇄하려면 printf()
일치하는 지정자가 필요합니다 : "%d"
. 이것은 C ++에서 cout
.
현명한 우려 : 줄 번호가 INT_MAX
1을 초과하면 (16 비트로 다소 생각할 수 있음 int
) 컴파일러가 경고를 생성하기를 바랍니다. 예:
format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
또는 코드는 이러한 경고를 방지하기 위해 더 넓은 유형을 강제 할 수 있습니다.
printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));
기피 printf()
모든 정수 제한을 피하려면 : stringify . 코드는 printf()
호출 없이 직접 인쇄 할 수 있습니다 . 오류 처리 2 에서 피하는 것이 좋습니다 .
#define xstr(a) str(a)
#define str(a) #a
fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);
1 그렇게 큰 파일을 갖는 것은 확실히 좋지 않은 프로그래밍 관행이지만 기계 생성 코드는 높을 수 있습니다.
2 디버깅에서 때때로 코드가 원하는대로 작동하지 않는 경우가 있습니다. 다음과 같은 복잡한 함수를 호출 *printf()
하면 간단한 fputs()
.