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