当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《有没有人曾经使用__COUNTER__预处理器宏?》经验,为你挑选了5个好方法。

__COUNTER__符号由VC++和GCC提供,并在每次使用时提供增加的非负积分值.

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



1> 小智..:

__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 );
  // ...
}

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


为什么需要MACRO_CONCAT和CONCAT_IMPL?我们不能直接写`LockUse ## __ COUNTER__`?
@Cœur - 仅供参考,几年前我在这个网站上问了同样的问题:[*为什么这个连接宏需要一个间接级别?*](http://stackoverflow.com/questions/19666142/why-是-A-级的-间接需要的换这个-级联宏)
使用单个`use_lock(g_Lock1,g_Lock2)`函数是一个明智的好主意,该函数足够智能地命令锁定以避免死锁.

2> Michael Burr..:

我在编译时断言宏中使用它让宏为typedef创建一个唯一的名称.看到

在C语言中在构建时ASSERT表达式的方法

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


我认为,等效定义至少在C89中是错误的.我认为C99和C++ 11都允许冗余的typedef,但并不总是允许它们.

3> Charlie Mart..:

除了DEBUG宏之外,我从未使用它.能够说得很方便

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


有趣.但是这比使用__FILE__更好/更好.毕竟,这将告诉您航路点的确切位置,而不是必须在文件中搜索WAYPOINT实例?我错过了什么;-)
第二个分号会使它失败,比如`if(foo)WAYPOINT; else bar();`.你重新介绍了`do {foo} while(0)`solves :)的问题
不,没有.它是故意的.如果有人写WAYPOINT; 额外的; 是一个无操作,默默地优化出来.从另一个方面做它,它可以成为宏的南部某处的语法错误,原因隐藏在宏体中.
@CharlieMartin宏中的'do {foo} while(0)`的重点是避免使用`if` /`else`语句的问题.如果你不担心if语句是否没有括号(这是公平的),为什么不删除整个`while(0)`包装器?无论哪种方式,`while(0)`包装器使用尾随分号完全没有意义.
我再次:在做{}的同时(0),顺便说一句.:-)
好吧,您可能会想念我,说:“这是*所有*,我发现它对您有用。” 哪一个不是
在这种情况下,您确实需要删除结尾的分号!这就是我所说的“无论如何……”的意思。

4> JamieH..:

它在xCover代码覆盖库中使用,用于标记执行所经过的行,以查找未覆盖的行.



5> Potatoswatte..:

我有兴趣了解是否有人曾经使用它,

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

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

以及它是否值得标准化?

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

违反单定义规则非常难以捕获并可能产生错误和安全风险.少数用例__COUNTER__并没有真正超过缺点和缺乏可扩展性.

即使您从未提供使用的代码,__COUNTER__在对枚举序列进行原型设计时也很有用,这样可以省去在具体成员资格之前分配名称的麻烦.

推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有