태그 보관물: c-preprocessor

c-preprocessor

매크로를 사용하여 소스 파일 라인을 계산합니까? / C ++

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__입니다.

GodBolt에서 작동 .

내 카운터를 배치하여 – 당신은 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__기반의 하나는 동일하게 작동합니다.

constexprC ++에서 s뿐만 아니라 작동 enum하지만 enum일반 C에서도 작동합니다 (위의 솔루션은 일반 C 솔루션입니다).


답변