有没有人曾经使用过__COUNTER__预处理器macros?

__COUNTER__符号由VC ++和GCC提供,并在每次使用时给出一个递增的非负整数值。

我有兴趣了解是否有人曾经使用过它,这是否值得标准化?

它被用在xCover代码覆盖库中,用来标记执行过的行,find没有被覆盖的行。

__COUNTER__在需要唯一名称的任何地方__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_use4lock_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 ); // ... } 

但是不要挂在我称为对象锁的事实上 – 任何需要在匹配对中调用的函数都适合这种模式。 您甚至可能在给定块中的同一“locking”上有多个用途。

我已经在一个编译时断言macros中使用它,让这个macros为一个独特的typedef创build一个名字。 看到

  • 在构build时在C中ASSERTexpression式的方法

如果你想要血淋淋的细节。

我从来没有用过任何东西,除了一个DEBUGmacros。 能说的很方便

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

我很想知道是否有人曾经使用它,

是的,但正如您在本问答中的许多例子所看到的那样,标准化的__LINE__在大多数情况下也是足够的。

__COUNTER__只有在计数必须每次增加1的情况下才是真正必要的,或者它必须具有多个#include文件的连续性。

而且这是否值得标准化呢?

__LINE__不同, __COUNTER__是非常危险的,因为它取决于包含哪些头文件以及顺序。 如果两个.cpp文件(翻译单元)包含使用__COUNTER__的头文件,但头文件在不同实例中获得不同的计数序列,则它们可能会使用同一事物的不同定义并违反单定义规则。

一个定义违反规则很难被捕获,并可能造成错误和安全风险。 less数__COUNTER__用例并不是真正的缺点,缺less可扩展性。

即使您从未运送使用__COUNTER__代码,在原型化枚举序列时也可能很有用,从而避免了在成员资格具体化之前分配名称的麻烦。

如果我正确地理解了这些function,我希望在使用Perl时可以使用该function,并将事件loggingfunction添加到现有的GUI中。 我想确保所需的手动testing(叹气)给了我们全面的覆盖,所以我将每个testing点logging到一个文件中,并且logging一个__counter__值可以很容易地看到覆盖范围内缺less的内容。 事实上,我手工编码的等值。

我用它在本文中生成独特的types: http : //www.codeproject.com/Articles/42021/Sealing-Classes-in-C

它被Boost.Asio用来实现无堆栈协程。

头文件: http : //www.boost.org/doc/libs/1_61_0/boost/asio/coroutine.hpp

示例可以在这里find: http : //www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/example/cpp03/http/server4/request_parser.cpp

我打算使用__COUNTER__给我们的代码库中的每个文件一个唯一的标识符,以便这个唯一的代码可以用于在embedded式系统中loggingASSERT。

这种方法比使用string存储文件名(使用__FILE__ )更有效率,特别是在embedded式系统上使用微型ROM。 在阅读本文时,我想到了这个想法 – 在Embedded.com上声明自己 。 可惜的是,它只适用于基于GCC的编译器。

我正在使用这个variables在PRNG(伪随机数生成器)中引入一些熵。 每次我打电话给PRNG,我都可以用这个variables来提供一些熵。 从长远来看,如果PRNG的调用是随机的,因为它取决于用户的行为,那么一些熵会被添加到生成器中。

__COUNTER__保证是唯一的,不像__LINE__ 。 一些编译器允许__LINE__被重置。 #include文件也将重置__LINE__

用法在TensorFlow的REGISTER_KERNEL_BUILDERmacros中 。 每个TensorFlow Op可以有一个或多个内核作为其实现。 这些内核是在注册商处注册的。 内核的注册是通过定义一个全局variables完成的 – variables的构造函数可以进行注册。 在这里作者使用__COUNTER__给每个全局variables一个唯一的名字。

 #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); \ });