Count source file lines using macros?

For completeness: If you're willing to add MAGIC2 after every line, you can use __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 (returns 3)

You can make it reusable by storing the start and end values of __COUNTER__.

Overall this is really cumbersome though. You also won't be able to count lines that contain preprocessor directives or that end with // comments. I'd use __LINE__ instead, see the other answer.


A somewhat more robust solution, allowing for different counters (as long as they don't intermix, and there's no use of __COUNTER__ for other tasks):

#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 };

This hides the implementation details (although it hides them inside macros...). It is a generalization of @MaxLanghof's answer. Note that __COUNTER__ may have a non-zero value when we start a count.

Here's how it's used:

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;
}

Also, this is valid C - if your preprocessor supports __COUNTER__, that is.

Works on GodBolt.

If you're using C++, you can modify this solution to not even pollute the global namespace - by placing the counters within namespace macro_based_line_counts { ... }, or namespace detail etc.)


I know that the OP's request is to use macros, but I would like to add another way of doing this that does not involve using macros.

C++20 introduces the source_location class that represents certain information about the source code, such as file names, line numbers, and function names. We can use that pretty easily in this case.

#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;
}

And live example here.


There is the __LINE__ preprocessor macro which gives you an integer for the line is appeared on. You could take its value on some line, and then some later line, and compare.

static const int BEFORE = __LINE__;
foo();
bar();
baz();
quux();
static const int AFTER = __LINE__;
static const int COUNT = AFTER - BEFORE - 1; // 4

If you want to count the occurrences of something rather than source lines, __COUNTER__ might be a non-standard option, supported by some compilers such as GCC and MSVC.

#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

I took the initial value of __COUNTER__ because it might have been used previously in the source file, or some included header.

In C rather than C++ there are limitations on constant variables, so an enum might be used instead.

enum MyEnum
{
    FOO = COUNT // C: error: enumerator value for ‘FOO’ is not an integer constant
};

Replacing the const with enum:

enum {BEFORE = __LINE__};
foo();
bar();
baz();
quux();
enum { COUNT = __LINE__ - BEFORE - 1};
enum MyEnum
{
    FOO = COUNT // OK
};