Возможно ли с помощью препроцессора 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).
- Очевидно, что это можно сделать, запустив исходный файл через сценарий внешнего процессора, но я не об этом.
c++
c-preprocessor
einpoklum
источник
источник
__LINE__
, которое представляет номер текущей строки__COUNTER__
и / илиBOOST_PP_COUNTER
ищите?int arr[MAGIC4]
и получения количества строк в некотором ранее подсчитанном разделе моего кода.Ответы:
Есть
__LINE__
макрос препроцессора, который дает вам целое число для строки, в которой он появился. Вы можете взять его значение в какой-то строке, а затем в более поздней строке и сравнить.Если вы хотите посчитать вхождения чего-то, а не исходные строки, это
__COUNTER__
может быть нестандартным вариантом, поддерживаемым некоторыми компиляторами, такими как GCC и MSVC.Я взял начальное значение,
__COUNTER__
потому что оно могло быть использовано ранее в исходном файле или в каком-то заголовке.В C, а не в C ++ существуют ограничения на постоянные переменные, поэтому
enum
вместо них можно использовать.Замена конста с помощью
enum
:источник
__COUNTER__
не является стандартным в C или C ++. Если вы знаете, что он работает с определенными компиляторами, укажите их.BEFORE
иAFTER
не макросыЯ знаю, что запрос OP - использовать макросы, но я хотел бы добавить другой способ сделать это, не связанный с использованием макросов.
C ++ 20 представляет
source_location
класс, который представляет определенную информацию об исходном коде, такую как имена файлов, номера строк и имена функций. Мы можем использовать это довольно легко в этом случае.И живой пример здесь .
источник
source_location
быть экспериментальным в C ++ 20?source_location
теперь официально является частью C ++ 20. Проверьте здесь . Я просто не смог найти версию компилятора gcc на godbolt.org, которая уже поддерживает его в неэкспериментальном смысле. Не могли бы вы объяснить немного больше вашего утверждения - я могу использовать количество строк только в той же области, что и подсчитанные мной строки ?line_number_start
иline_number_end
в этой области, нигде больше. Если я хочу это в другом месте, мне нужно передать его во время выполнения - что побеждает цель.line_number_end
видимым во время компиляции вне его контекста. Поправьте меня если я ошибаюсь.Для полноты: если вы хотите добавить
MAGIC2
после каждой строки, вы можете использовать__COUNTER__
:https://godbolt.org/z/i8fDLx (возвращается
3
)Вы можете сделать его многоразовым, сохранив начальные и конечные значения
__COUNTER__
.В целом это действительно громоздко, хотя. Вы также не сможете сосчитать строки, содержащие директивы препроцессора или заканчивающиеся
//
комментариями. Я бы использовал__LINE__
вместо этого, увидеть другой ответ.источник
static_assert
?__COUNTER__
что изначально он все еще равен нулю, поскольку другие заголовки и т. Д. Могут его использовать.__COUNTER__
дважды и взять разницу__COUNTER__
по себе @ прежняя известная_463035818 не будет допущена, и ей нужно что-то расширять, иначе это не будет учитываться (я не могу запомнить правила на 100%).Несколько более надежное решение, позволяющее использовать разные счетчики (если они не смешиваются и не используются
__COUNTER__
для других задач):Это скрывает детали реализации (хотя и скрывает их внутри макросов ...). Это обобщение ответа @ MaxLanghof. Обратите внимание, что
__COUNTER__
может иметь ненулевое значение, когда мы начинаем подсчет.Вот как это используется:
Кроме того, это действительно C - если ваш препроцессор поддерживает
__COUNTER__
, то есть.Работает на GodBolt .
Если вы используете C ++, вы можете изменить это решение, чтобы оно даже не загрязняло глобальное пространство имен - путем размещения счетчиков внутри
namespace macro_based_line_counts { ... }
иnamespace detail
т. Д.)источник
Исходя из вашего комментария, если вы хотите указать размер массива (во время компиляции) в C или C ++, вы можете сделать
Если вам нужны
sizeof(array)
промежуточные строки, вы можете заменить его ссылкой на статическую переменную (если это не обязательно должно быть целочисленное константное выражение), а оптимизирующий компилятор должен обрабатывать его точно так же (исключая необходимость размещения статической переменной в памяти)Решение на
__COUNTER__
основе (если это расширение доступно) в отличие от решения на__LINE__
основе будет работать так же.constexpr
s в C ++ должен работать так же хорошоenum
, ноenum
будет работать и в простом C (мое решение выше - простое решение C).источник
__COUNTER__
основе также имеет проблемы: вам лучше надеяться, что ваш волшебный макрос - единственный пользователь__COUNTER__
, по крайней мере, до того, как вы закончили с его использованием__COUNTER__
. Проблема в основном сводится к простым фактам, которые__COUNTER__/__LINE__
являются особенностями препроцессора, и препроцессор работает за один проход, поэтому вы не можете потом добавить целочисленное константное выражение на основе__COUNTER__
/__LINE__
. Единственный способ (по крайней мере, в C) - это избежать необходимости, например, используя объявления массива вперед без размера (объявления не полностью типизированного массива).\
это не влияет__LINE__
- если есть разрыв строки,__LINE__
увеличивается. Пример 1 , пример 2 .