14

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.
11
  • 6
    There's a macro called __LINE__ that represents the current line number Commented Jan 8, 2020 at 10:49
  • 2
    Are searching for __COUNTER__ and/or BOOST_PP_COUNTER? Commented Jan 8, 2020 at 10:53
  • 11
    What is the actual problem you need to solve? Why do you need this? Commented Jan 8, 2020 at 10:58
  • 1
    Does this help? Commented Jan 8, 2020 at 10:59
  • 1
    @PSkocik: I want something I could use as a compile-time constant, e.g. for saying int arr[MAGIC4] and get the number of lines in some previously-counted section of my code. Commented Jan 8, 2020 at 11:04

5 Answers 5

15

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 }; 
Sign up to request clarification or add additional context in comments.

6 Comments

I think this is about the closest as you can get with just the preprocessor. The preprocessor is one-pass, so you can't backpatch a later computed value, but global-variable references will work and should optimize the same. They just won't work at integer constants expressions, but it might be possible to structure the code so that those aren't needed for the counts.
__COUNTER__ is not standard in C or C++. If you know it works with particular compilers, specify them.
@einpoklum no, BEFORE and AFTER aren't macros
There's a problem with the non-counter version of this solution: the before and after are usable only in the same scope as the source lines. Edited my "e.g." snippet to reflect that this is an issue.
@user694733 True question was tagged [C++]. For C enum constants work.
|
9

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.

9 Comments

Without macros is even better than with macros. However - with this approach, I can only use the line count in the same scope as the lines I've counted. Also - with source_location be experimental in C++20?
I agree that solution without macros is far better than with macros. source_location is now officially part of C++20. Check here. I just couldn't find the version of gcc compiler on godbolt.org that already supports it in non experimental sense. Can you please explain a bit more your statement - I can only use the line count in the same scope as the lines I've counted?
Suppose I put your suggestion within a function (i.e. the lines counted are invocations, not declarations). It works - but I only have line_number_start and line_number_end within that scope, nowhere else. If I want it elsewhere I need to pass it at run-time - which defeats the purpose.
Take a look at the example that standard provides here. If it is default argument, then it is still part of compile-time, right?
Yes, but that doesn't make line_number_end visible at compile-time outside its scope. Correct me if I'm wrong.
|
7

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.

4 Comments

why do you use static_assert ?
This gave "9" in the source file i dropped it into, you can't assume __COUNTER__ is still zero initially as other headers, etc. might use it.
you have to use the value of __COUNTER__ twice and take the difference
@formerlyknownas_463035818 __COUNTER__ on it's own wouldn't be allowed, and it needs to get expanded to something or it won't count (I can't remember the rules 100% on this).
7

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.)

Comments

5

Based on your comment, if you want to specify a (compile-time) array size in C or C++, you can do

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[] 

If you need sizeof(array) in the intervening lines, you can replace it with a static variable reference (unless it absolutely needs to be an integer constant expression) and an optimizing compiler should treat it just the same (eliminate the need for the static variable to be placed in memory)

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 

A __COUNTER__-based solution (if that extension is available) as opposed to a __LINE__-based one will work the same.

constexprs in C++ should work as well as enum, but enum will work in plain C as well (my solution above is a plain C solution).

4 Comments

This will work only if my use of the line-count is in the same scope as the counted lines. IIANM. Note I edited my question slightly to emphasize that could be an issue.
@einpoklum A __COUNTER__ based solution has issues too: you better hope your magic macro is the only user of __COUNTER__, at least before you're done with your use of __COUNTER__. The problem basically all comes down to the simple facts that __COUNTER__/__LINE__ are preprocessor features and the preprocessor works in one pass, so you can't backpatch an integer constant expression later based on __COUNTER__/__LINE__. The only way (in C at least) is to avoid the need in the first place, e.g., by using forward array declarations without size (incompletely typed array declarations).
For the record, the \ does not affect __LINE__ - if there is a line break, __LINE__ increases. Example 1, example 2.
@MaxLanghof Thanks. Didn't realize that. Fixed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.