是否可以使用方法返回使用#define 创建的变量?

Posted

技术标签:

【中文标题】是否可以使用方法返回使用#define 创建的变量?【英文标题】:Is it possible to use a method to return a variable created using #define? 【发布时间】:2015-03-05 16:33:40 【问题描述】:

所以想象一下我有代码:

#define ID_BUTTON 1

为了给自己一个变量,以便在使用CreateWindow()函数创建按钮时使用。

现在,我可以使用返回 ID_BUTTON 的方法吗?通常我会发现它相对容易,但我不知道我必须指定什么函数类型。

所以,

1) 有可能吗?

2) 如果是这样,我必须使用什么函数类型?

请记住,它只是简单的代码,例如:

<function_type> getID() 
return ID_BUTTON;

谢谢,

【问题讨论】:

你问的是1的类型吗?如果是,那就是int en.cppreference.com/w/cpp/language/integer_literal 当您使用ID_BUTTON 时,在编译器编译该函数时它实际上已替换为1 (如果 ID_BUTTON 可以是1 "hello world",那么你已经有麻烦了。) @user2864740,在这种情况下,根据您想要的行为,您可以使用auto getID()decltype(ID_BUTTON) getId() 【参考方案1】:

从技术上讲,使用 C++11 decltype实际上可以实现您想要的:

#define ID_BUTTON 1

auto getID() -> decltype(ID_BUTTON)

    return ID_BUTTON;


int main()

    auto x = getID();

在那里,无需在任何地方为ID_BUTTON 或函数指定int

但是,您的问题的真正答案应该是:不要将宏用于常量。 C++ 有 const(以及最近的 constexpr)。 p>

【讨论】:

对于ID_BUTTON,如果他有一个资源文件,他将不得不使用#define,除非他想要两个单独的头文件,一个用于C++,一个用于资源文件。 @andlabs:是的,好点子。我的建议是严格的 C++ 语言级别。 仍然是有价值的信息;我在回答中指出了这篇文章(其中涵盖了不同的内容,例如控件标识符)。【参考方案2】:

假设你不明白什么

#define ID_BUTTON 1

甚至:

#defineconstconstexprenum 语句不创建变量;他们创建cconstants。变量和常量都是标识符,它们引用程序中的值。区别在于常量不能在运行时改变,而变量可以。

#define 不创建任何普通常量,但是。它实际上告诉编译器的一部分称为预处理器,将源代码中的文本ID_BUTTON 实际替换 为字符串1。这可能很有用,这是您必须为 C 做的事情,但在 C++ 中,constexpr(在 C++11 中引入)通常更理想。有关更多信息,请参阅 Christian Hackl 的回答。

如果您打算使用常量将值传递给 API,这是您计划使用 ID_BUTTON 执行的操作,API 通常会告诉您它期望的类型,因此您可以使用该类型而不是让编译器确定工作的最佳类型。但是,请参阅下面关于 Windows 中的控件标识符的讨论,因为 ID_BUTTON 的特定情况有一个问题。

如果您可以控制类型,则必须花更多的心思来确定要使用的类型。在某些情况下,语言的类型提升规则可以让你在没有类型的情况下只说1,但如果你要创建已知的小整数或大整数、位字段或浮点数,你需要使用适当的类型名称或限定符(shortlongunsignedfloatdouble 等)。弄清楚去哪里需要一点时间,但是一旦你做的足够多,你就会自然而然地去做。


假设您不了解 Windows 中的控件标识符的工作原理:

大部分采用控制标识符的API函数,如GetDlgItem(),将控制标识符作为int;因此,您的控件标识符应具有 int 类型。

但是,CreateWindow()CreateWindowEx() 期望控件标识符作为倒数第三个参数。此参数的类型为HMENU。 C++ 不会让您将int 推入HMENU,因此您必须使用演员表:(HMENU) ID_BUTTON。 (可能有一个等效的 C++ 风格的演员表,但我不知道/忘记它是什么。)

此外,如果您要使用资源文件,则必须使用#define 语句来创建ID_xxx 常量名称,因为资源文件格式没有没有constconstexprenum。在这种情况下,继续使用 #define 作为标识符,将这些 #defines 放入它们自己的包含文件中,并将 #include 从 C++ 源文件和资源文件中放入该文件。

如果您使用资源文件,则根本不必担心使用控件标识符;只需对每个控件直接使用HWND。如果您需要在窗口中进行选项卡导航或其他对话框消息处理,您仍然应该分配控件标识符,但除此之外,您可以直接使用HWNDs。 (我忘记了标签导航中是否涉及控件标识符。)

最后,有许多对对话管理器具有特殊意义的预定义控件标识符。这是来自微软的 winuser.h:

/*
 * Dialog Box Command IDs
 */
#define IDOK                1
#define IDCANCEL            2
#define IDABORT             3
#define IDRETRY             4
#define IDIGNORE            5
#define IDYES               6
#define IDNO                7
#if(WINVER >= 0x0400)
#define IDCLOSE         8
#define IDHELP          9
#endif /* WINVER >= 0x0400 */

您自己的控件标识符应避免与这些冲突;您的 ID_BUTTONIDOK 冲突。 (如果它们确实发生冲突,您会看到奇怪的事情,例如,您的控件在对话框管理器知道的键盘快捷键上激活。)此问题的规范解决方案是在 100 开始对控件标识符进行编号(我相信Visual Studio 对此负责,但我不确定)。

【讨论】:

#define 不会创建常量。当我写foo(ID_BUTTON); 时,没有常数。只是一个预处理器宏扩展和一个int 文字。 对;我的意思是以简单的方式区分变量和常量。我会在下一段中讨论预处理器的替换。

以上是关于是否可以使用方法返回使用#define 创建的变量?的主要内容,如果未能解决你的问题,请参考以下文章

define定义变量

PHP中empty()和isset()的区别

是否可以在 Adob​​e Flex 中进行#define?

可以使用命令define定义变量吗

c语言define用法是啥

用#define 定义的常量与变量有啥区别,啥时候应该使用define定义符号常量