Подтвердить что ты не робот

Кто-нибудь когда-либо использовал макрос __COUNTER__ pre-processor?

Символ __COUNTER__ предоставляется VС++ и GCC и дает все возрастающее неотрицательное целочисленное значение каждый раз, когда он используется.

Мне интересно узнать, кто-нибудь когда-либо использовал его, и будет ли это что-то, что стоит стандартизировать?

4b9b3361

Ответ 1

Он используется в xCover библиотеке покрытия кода, чтобы пометить строки, выполнение которых проходит, чтобы найти те, которые не покрыты.

Ответ 2

__COUNTER__ полезен везде, где вам нужно уникальное имя. Я использовал его широко для замков и стеков стиля RAII. Рассмотрим:

struct TLock
{
  void Lock();
  void Unlock();
}
g_Lock1, g_Lock2;

struct TLockUse
{
  TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); }
  ~TLockUse(){ m_Lock.Unlock(); }

  TLock &m_Lock;
};

void DoSomething()
{
  TLockUse lock_use1( g_Lock1 );
  TLockUse lock_use2( g_Lock2 );
  // ...
}

Достаточно назвать использование блокировок и даже стать источником ошибок, если они не все объявлены в верхней части блока. Откуда вы знаете, находитесь ли вы на lock_use4 или lock_use11? Это также ненужное загрязнение пространства имен - мне никогда не нужно ссылаться на объекты использования блокировки по имени. Поэтому я использую __COUNTER__:

#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock )

void DoSomething2()
{
  USE_LOCK( g_Lock1 );
  USE_LOCK( g_Lock2 );
  // ...
}

Но не зацикливайтесь на том, что я вызывал блокировки объектов - любая функция (ы), которая должна быть вызвана в соответствующие пары, соответствует этому шаблону. Возможно, у вас может быть несколько применений в одной и той же "блокировке" в данном блоке.

Ответ 4

Я никогда не использовал его ни для чего, кроме макроса DEBUG. Удобно говорить

#define WAYPOINT \
    do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);

Ответ 5

Мне интересно узнать, кто-нибудь когда-либо использовал его,

Да, но, как вы можете видеть из многих примеров в этом стандарте, Q & A, __LINE__, также будет достаточным в большинстве случаев.

__COUNTER__ действительно необходим только в случаях, когда счетчик должен увеличиваться на единицу каждый раз или должен иметь непрерывность в нескольких файлах #include.

и будет ли это что-то, что стоит стандартизировать?

__COUNTER__, в отличие от __LINE__, очень опасен, потому что зависит от того, какие файлы заголовков включены и какой порядок. Если два файла .cpp (единицы перевода) включают заголовочный файл, который использует __COUNTER__, но заголовочный файл получает разные последовательности отсчетов в разных экземплярах, они могут использовать разные определения одной и той же вещи и нарушать одно правило определения.

Нарушения правил с одним определением очень сложно поймать и потенциально создать ошибки и риски безопасности. Несколько вариантов использования __COUNTER__ на самом деле не перевешивают недостаток и отсутствие масштабируемости.

Даже если вы никогда не отправляете код, который использует __COUNTER__, он может быть полезен при прототипировании последовательности перечислений, что избавит вас от необходимости назначать имена до того, как членство будет конкретным.

Ответ 6

Если я правильно понимаю функциональность, я хотел, чтобы у меня была такая функциональность, когда я работал в Perl, добавив функцию регистрации событий в существующий графический интерфейс. Я хотел убедиться, что необходимое ручное тестирование (вздох) дало нам полный охват, поэтому я зарегистрировал каждую тестовую точку в файле, и запись значения __counter__ позволила легко увидеть, чего не хватает в покрытии. Как бы то ни было, я передал закодированный эквивалент.

Ответ 9

Я намерен использовать __COUNTER__, чтобы дать каждому файлу в нашей базе кода уникальный идентификатор, чтобы этот уникальный код можно было использовать при регистрации ASSERT во встроенной системе.

Этот метод намного эффективнее, чем использование строк для хранения имен файлов (с использованием __FILE__), особенно во встроенной системе с маленьким ROM. Я думал об этой идее, пока я читал эту статью - Assert Yourself на Embedded.com. Позор, что он работает только с компиляторами на основе GCC.

Ответ 10

Я использую эту переменную, чтобы ввести некоторую энтропию в PRNG (генератор псевдослучайных чисел). Каждый раз, когда я вызываю PRNG, я могу предоставить некоторую энтропию, используя эту переменную. В конечном счете, если вызовы PRNG являются случайными, поскольку они зависят от действий пользователя, в генератор будет добавлена ​​некоторая энтропия.

Ответ 11

__COUNTER__ гарантированно будет уникальным, в отличие от __LINE__. Некоторые компиляторы позволяют __LINE__ быть reset. #include файлы также будут reset __LINE__.

Ответ 12

Использование макрос TensorFlow REGISTER_KERNEL_BUILDER. Каждый TensorFlow Op может иметь одно или несколько ядер в качестве своих реализаций. Эти ядра регистрируются у регистратора. Регистрация ядра выполняется путем определения глобальной переменной - конструктор переменной может выполнить регистрацию. Здесь авторы используют __COUNTER__, чтобы дать каждой глобальной переменной уникальное имя.

#define REGISTER_KERNEL_BUILDER(kernel_builder, ...) \
  REGISTER_KERNEL_BUILDER_UNIQ_HELPER(__COUNTER__, kernel_builder, __VA_ARGS__)

#define REGISTER_KERNEL_BUILDER_UNIQ_HELPER(ctr, kernel_builder, ...) \
  REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, __VA_ARGS__)

#define REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, ...)          \
  static ::tensorflow::kernel_factory::OpKernelRegistrar                \
  registrar__body__##ctr##__object(                                 \
      SHOULD_REGISTER_OP_KERNEL(#__VA_ARGS__)                       \
      ? ::tensorflow::register_kernel::kernel_builder.Build()   \
      : nullptr,                                                \
      #__VA_ARGS__, [](::tensorflow::OpKernelConstruction* context) \
            -> ::tensorflow::OpKernel* {                \
              return new __VA_ARGS__(context);          \
            });

Ответ 13

Используется в метрической системе ClickHouse.

namespace CurrentMetrics
{
    #define M(NAME) extern const Metric NAME = __COUNTER__;
        APPLY_FOR_METRICS(M)
    #undef M
    constexpr Metric END = __COUNTER__;

    std::atomic<Value> values[END] {};    /// Global variable, initialized by zeros.

    const char * getDescription(Metric event)
    {
        static const char * descriptions[] =
        {
        #define M(NAME) #NAME,
            APPLY_FOR_METRICS(M)
        #undef M
        };

        return descriptions[event];
    }

    Metric end() { return END; }
}