C / C ++ 전처리기를 사용하여 소스 파일 내의 행을 매크로 또는 컴파일 가능한 시간 값으로 계산할 수 있습니까? 예 나는 대체 할 수있는 MAGIC1
, MAGIC2
그리고 MAGIC3
사용할 때 다음에, 어떻게 든 값 4를 얻을 MAGIC3
?
MAGIC1 // can be placed wherever you like before the relevant
// lines - either right before them, or in global scope etc.
foo(); MAGIC2
bar(); MAGIC2
baz(); MAGIC2
quux(); MAGIC2
// ... possibly a bunch of code here; not guaranteed to be in same scope ...
MAGIC3
노트:
- 전 처리기 기능에 대한 컴파일러 별 확장은 허용되지만 바람직하지 않습니다.
- 이것이 C와 대조적으로 C ++의 일부의 도움으로 만 가능하다면, 그것은 수용 가능하지만 바람직하지 않습니다 (즉, C에서 작동하는 것을 원합니다).
- 분명히 이것은 외부 프로세서 스크립트를 통해 소스 파일을 실행하여 수행 할 수 있지만 이것이 내가 요구하는 것은 아닙니다.
답변
__LINE__
선에 대한 정수를 제공 하는 전 처리기 매크로가 있습니다. 당신은 그것의 가치를 어떤 줄에서 취한 다음 나중의 줄에서 가져 와서 비교할 수 있습니다.
static const int BEFORE = __LINE__;
foo();
bar();
baz();
quux();
static const int AFTER = __LINE__;
static const int COUNT = AFTER - BEFORE - 1; // 4
소스 라인이 아닌 무언가의 발생을 계산하려면 GCC 및 MSVC와 같은 일부 컴파일러 __COUNTER__
에서 지원하는 비표준 옵션이 될 수 있습니다 .
#define MAGIC2_2(c)
#define MAGIC2(c) MAGIC2_2(c)
static const int BEFORE = __COUNTER__;
void foo(); MAGIC2(__COUNTER__);
void bar(
int multiple,
float lines); MAGIC2(__COUNTER__);
void baz(); MAGIC2(__COUNTER__);
void quux(); MAGIC2(__COUNTER__);
static const int AFTER = __COUNTER__;
static const int COUNT = AFTER - BEFORE - 1; // 4
__COUNTER__
소스 파일이나 일부 포함 된 헤더에서 이전에 사용되었을 수 있으므로 초기 값을 사용했습니다.
C ++ 대신 C에서는 상수 변수에 제한 enum
이 있으므로 대신 a를 사용할 수 있습니다.
enum MyEnum
{
FOO = COUNT // C: error: enumerator value for ‘FOO’ is not an integer constant
};
const를 enum
다음 과 같이 바꾸십시오 .
enum {BEFORE = __LINE__};
foo();
bar();
baz();
quux();
enum { COUNT = __LINE__ - BEFORE - 1};
enum MyEnum
{
FOO = COUNT // OK
};
답변
OP의 요청은 매크로를 사용하는 것이지만 매크로를 사용하지 않는 다른 방법을 추가하고 싶습니다.
C ++ 20에는 source_location
파일 이름, 줄 번호 및 함수 이름과 같은 소스 코드에 대한 특정 정보를 나타내는 클래스가 도입되었습니다 . 이 경우에는 쉽게 사용할 수 있습니다.
#include <iostream>
#include <source_location>
static constexpr auto line_number_start = std::source_location::current().line();
void foo();
void bar();
static constexpr auto line_number_end = std::source_location::current().line();
int main() {
std::cout << line_number_end - line_number_start - 1 << std::endl; // 2
return 0;
}
답변
완벽을 기하기 위해 : MAGIC2
매 줄마다 추가 하고 싶다면 다음을 사용할 수 있습니다 __COUNTER__
.
#define MAGIC2 static_assert(__COUNTER__ + 1, "");
/* some */ MAGIC2
void source(); MAGIC2
void lines(); MAGIC2
constexpr int numberOfLines = __COUNTER__;
int main()
{
return numberOfLines;
}
https://godbolt.org/z/i8fDLx (반환3
)
시작 값과 끝 값을 저장하여 재사용 할 수 있습니다. __COUNTER__
.
전반적으로 이것은 실제로 성가시다. 또한 전 처리기 지시문을 포함하거나 //
주석으로 끝나는 줄을 계산할 수 없습니다 . 내가 사용하는 것 __LINE__
대신에 다른 대답을 참조하십시오.
답변
서로 다른 카운터를 사용할 수 있고 (다른 카운터를 사용하지 않는 한) 다른 카운터를 허용하는 다소 강력한 솔루션 __COUNTER__
:
#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#define COUNT_THIS_LINE static_assert(__COUNTER__ + 1, "");
#define START_COUNTING_LINES(count_name) \
enum { EXPAND_THEN_CONCATENATE(count_name, _start) = __COUNTER__ };
#define FINISH_COUNTING_LINES(count_name) \
enum { count_name = __COUNTER__ - EXPAND_THEN_CONCATENATE(count_name, _start) - 1 };
이것은 구현 세부 사항을 숨 깁니다 (매크로 안에 숨기는 경우에도 …). @MaxLanghof의 답변을 일반화했습니다. 참고__COUNTER__
우리는 수를 시작할 때 아닌 값을 가질 수있다.
사용 방법은 다음과 같습니다.
START_COUNTING_LINES(ze_count)
int hello(int x) {
x++;
/* some */ COUNT_THIS_LINE
void source(); COUNT_THIS_LINE
void lines(); COUNT_THIS_LINE
return x;
}
FINISH_COUNTING_LINES(ze_count)
int main()
{
return ze_count;
}
또한 이것은 전처리 기가를 지원하는 경우 유효한 C __COUNTER__
입니다.
내 카운터를 배치하여 – 당신은 C를 사용하는 경우 ++, 당신도 글로벌 네임 스페이스를 오염시키지에이 솔루션을 수정할 수 있습니다 namespace macro_based_line_counts { ... }
, 또는 namespace detail
등)
답변
C 또는 C ++에서 (컴파일 타임) 배열 크기를 지정하려면 주석을 기반으로 할 수 있습니다
int array[]; //incomplete type
enum{ LINE0 = __LINE__ }; //enum constants are integer constant expressions
/*lines to be counted; may use array (though not sizeof(array)) */
/*...*/
int array[ __LINE__ - LINE0 ]; //complete the definition of int array[]
sizeof(array)
중간 줄에 필요한 경우 정적 변수 참조로 대체 할 수 있으며 (정수 상수 표현식이 아닌 경우) 최적화 컴파일러는 동일하게 처리해야합니다 (정적 변수를 배치 할 필요가 없음) 메모리에)
int array[]; static int count;
enum{ LINE0 = __LINE__ }; //enum constants are integer constant expressions
//... possibly use count here
enum { LINEDIFF = __LINE__ - LINE0 };
int array[ LINEDIFF ]; /*complete the definition of int array[]*/
static int count = LINEDIFF; //fill the count in later
__COUNTER__
A를 반대 기반 솔루션 (즉, 확장 가능한 경우) __LINE__
기반의 하나는 동일하게 작동합니다.
constexpr
C ++에서 s뿐만 아니라 작동 enum
하지만 enum
일반 C에서도 작동합니다 (위의 솔루션은 일반 C 솔루션입니다).