【问题标题】:Macros and Visual C++宏和 Visual C++
【发布时间】:2009-03-17 02:13:54
【问题描述】:

我正在尝试更好地了解宏在现代 C++ 和 Visual C++ 中的位置(如果有),还参考了 Windows 编程库:什么问题(如果有)宏解决了这些不使用就无法解决的情况?

我记得在this blog post 中读到了有关 Google Chrome 对宏(除其他外)使用 WTL 的信息,它们也用于 MFC - 这是该博客文章中的一个宏示例,我想在如果可能的话,最好的细节:

// CWindowImpl
BEGIN_MSG_MAP(Edit)
  MSG_WM_CHAR(OnChar)
  MSG_WM_CONTEXTMENU(OnContextMenu)
  MSG_WM_COPY(OnCopy)
  MSG_WM_CUT(OnCut)
  MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
  MSG_WM_KEYDOWN(OnKeyDown)
  MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
  MSG_WM_LBUTTONDOWN(OnLButtonDown)
  MSG_WM_LBUTTONUP(OnLButtonUp)
  MSG_WM_MBUTTONDOWN(OnNonLButtonDown)
  MSG_WM_MOUSEMOVE(OnMouseMove)
  MSG_WM_MOUSELEAVE(OnMouseLeave)
  MSG_WM_NCCALCSIZE(OnNCCalcSize)
  MSG_WM_NCPAINT(OnNCPaint)
  MSG_WM_RBUTTONDOWN(OnNonLButtonDown)
  MSG_WM_PASTE(OnPaste)
  MSG_WM_SYSCHAR(OnSysChar)  // WM_SYSxxx == WM_xxx with ALT down
  MSG_WM_SYSKEYDOWN(OnKeyDown)
END_MSG_MAP()

我在 MSDN 上阅读了 these articles 与宏有关的内容,但我也在尝试学习编写或避免宏以及在何处/何时使用它们的最佳实践。

【问题讨论】:

  • 感谢所有回复,“答案”分布在下面的所有三个回复中,这可能是我的问题碎片化的结果。将 jeffamaphone 的帖子标记为他的第一个答案,并解释了 MSG_WM_* 行为。

标签: c++ visual-c++ macros c-preprocessor


【解决方案1】:

所有这些宏都在公共 sdk 头文件中定义,因此您可以根据需要自行阅读它们的作用。基本上这里发生的是你正在使用宏生成一个 WndProc 函数。每个 MSG_WM_* 条目都是一个 case 语句,它通过将其参数从 wParam 和 lParam 转换为其原始类型并调用将这些类型作为参数(如果合适的话)的辅助函数(然后您可以实现)来处理给定的窗口消息。一些窗口消息有 0 或 1 个参数)。

在我看来,这一切都是废话。您不得不预先编写一堆样板,但作为交换,您使以后的调试变得更加困难。宏在我的现代编程世界中没有太多的位置,除了检查它们是否被定义。做流量控制的宏,或者假设特定的局部变量总是被定义的,等等,让我很不高兴。特别是当我必须调试它们时。

【讨论】:

  • 谢谢:我听说在现代 C++ 中应该避免使用宏(这是我的怀疑),我绝对同意。我仍然想了解阅读遗留代码时发生了什么 - 有没有可以推荐的链接来查看公共 SDK 头文件?
  • 像窗口程序这样的样板代码的宏实际上是一个真正的天赐之物。这种代码只是一遍又一遍地重复,永远不需要更改。最好的解决方案是为窗口过程使用 DSL,但如果没有这个,这些都很好
  • 节省打字是好的,但有一些微妙之处。例如,何时应该调用基类实现,或者对于新手甚至如何调用它都不明显。这类过于复杂的宏会导致难以发现的错误。有时间和地点,我同意。
  • 你可以在这里下载win32 SDK:microsoft.com/Downloads/…
  • @jeffmaphone:如果您正在编写普通的旧 Win32,也会出现同样的微妙之处 - 您总是需要知道何时应该调用 DefWndProc 以及各种参数的含义等等。一旦你掌握了这一点,那么宏将使你的代码更干净,并减少出错的机会
【解决方案2】:

Peter,你不妨问问 vi 还是 EMACS 是更好的编辑器。 (顺便说一下,EMACS。)很多人认为 C 预处理器是一个可怕的想法。其中包括 Stroustrup 和 Jim Gosling。这就是为什么 Java 没有预处理器,并且 Stroustrup 在 C++ 中放入了无数的东西,从 const 到模板,以避免使用预处理器。

还有其他人发现添加新语言很方便,就像在该代码中一样。

如果你阅读原始的 Bourne shell 代码,你会发现它看起来像

IF a == b THEN
   do_something();
   do_more();
ELSE
   do_less();
FI

Steve Bourne 基本上使用宏来赋予它类似 Algol68 的外观(那是当时非常酷的语言。)除了 Steve Bourne 之外的任何人都很难使用它。

然后看看 Obfuscated C 竞赛,其中一些最令人惊叹的混淆利用了 #define

就我个人而言,我并不太介意,虽然那个例子有点吓人(你如何调试它?)但是做那种事情是没有网络的;那里没有多少瓦伦达人。

【讨论】:

  • 谢谢:语言中的语言是一种很好的思考方式。您是否有任何“好”宏或您使用过的“不太介意”的宏的示例?
  • 我想不出我真正喜欢的复杂宏的任何用途。有时,就像在 Linux 内核中的宏中,它们是有原因的(内核中的内部循环被击中 lot);有时他们会实现 DSL,就像上面的例子一样。
  • 可能我曾经喜欢的最复杂的宏是日志记录宏,它为 C 实现了类似 log4j 的东西。
【解决方案3】:

(问题有点零散,但忽略了Windows部分):

X-Macros 使用预处理器避免代码重复。

【讨论】:

  • 感谢:虽然这篇文章是 2001 年的文章,但讨论了 60 年代汇编语言程序员使用的技巧,但读起来很有趣。文章中概述的 X 宏模式是否仍然适用于 2009 年在 C++ 中的使用,是否值得推荐?
  • 因为自 2001 年以来 C++ 还没有发展出真正的元语言,我想说这些技术仍然非常相关。它们在我的工作场所经常使用,以保持代码清洁和可维护。它们是完全在 C++ 中自动生成代码的少数明智的方法之一。
  • 顺便说一句,正如查理·马丁所说,这种技术不一定很好,但都是相对的——恕我直言,这是解决 C++ 中一些问题的最好方法,如果有的话,解决起来会好得多更好的元语言。 (C++ 实际上是 3 合一语法:日常代码、模板和预处理器。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 2014-09-04
  • 1970-01-01
  • 2016-12-14
相关资源
最近更新 更多