Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count source file lines using macros?

Is it possible, using the C/C++ preprocessor, to count lines within a source file, into either a macro or some kind compile-time-available value? E.g. can I replace MAGIC1, MAGIC2 and MAGIC3 in the following, and get the value 4 somehow when using 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

Notes:

  • Compiler-specific extensions to the preprocessor's capabilities are acceptable but undesirable.
  • If this is possible only with the help of some of C++, as opposed to C, construct, that's also acceptable but undesirable (i.e. I'd like something that would work for C).
  • Obviously this can be done by running the source file through some external processor script, but that's not what I'm asking.
like image 883
einpoklum Avatar asked Jan 08 '20 10:01

einpoklum


2 Answers

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
};
like image 182
Fire Lancer Avatar answered Nov 08 '22 12:11

Fire Lancer


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.

like image 9
NutCracker Avatar answered Nov 08 '22 12:11

NutCracker