是否可以使用方法返回使用#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
甚至:
#define
、const
、constexpr
和 enum
语句不创建变量;他们创建cconstants。变量和常量都是标识符,它们引用程序中的值。区别在于常量不能在运行时改变,而变量可以。
#define
不创建任何普通常量,但是。它实际上告诉编译器的一部分称为预处理器,将源代码中的文本ID_BUTTON
实际替换 为字符串1
。这可能很有用,这是您必须为 C 做的事情,但在 C++ 中,constexpr
(在 C++11 中引入)通常更理想。有关更多信息,请参阅 Christian Hackl 的回答。
如果您打算使用常量将值传递给 API,这是您计划使用 ID_BUTTON
执行的操作,API 通常会告诉您它期望的类型,因此您可以使用该类型而不是让编译器确定工作的最佳类型。但是,请参阅下面关于 Windows 中的控件标识符的讨论,因为 ID_BUTTON
的特定情况有一个问题。
如果您可以控制类型,则必须花更多的心思来确定要使用的类型。在某些情况下,语言的类型提升规则可以让你在没有类型的情况下只说1
,但如果你要创建已知的小整数或大整数、位字段或浮点数,你需要使用适当的类型名称或限定符(short
、long
、unsigned
、float
、double
等)。弄清楚去哪里需要一点时间,但是一旦你做的足够多,你就会自然而然地去做。
假设您不了解 Windows 中的控件标识符的工作原理:
大部分采用控制标识符的API函数,如GetDlgItem()
,将控制标识符作为int
;因此,您的控件标识符应具有 int
类型。
但是,CreateWindow()
和 CreateWindowEx()
期望控件标识符作为倒数第三个参数。此参数的类型为HMENU
。 C++ 不会让您将int
推入HMENU
,因此您必须使用演员表:(HMENU) ID_BUTTON
。 (可能有一个等效的 C++ 风格的演员表,但我不知道/忘记它是什么。)
此外,如果您要使用资源文件,则必须使用#define
语句来创建ID_xxx
常量名称,因为资源文件格式没有没有const
、constexpr
或enum
。在这种情况下,继续使用 #define
作为标识符,将这些 #define
s 放入它们自己的包含文件中,并将 #include
从 C++ 源文件和资源文件中放入该文件。
如果您不使用资源文件,则根本不必担心使用控件标识符;只需对每个控件直接使用HWND
。如果您需要在窗口中进行选项卡导航或其他对话框消息处理,您仍然应该分配控件标识符,但除此之外,您可以直接使用HWND
s。 (我忘记了标签导航中是否涉及控件标识符。)
最后,有许多对对话管理器具有特殊意义的预定义控件标识符。这是来自微软的 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_BUTTON
与 IDOK
冲突。 (如果它们确实发生冲突,您会看到奇怪的事情,例如,您的控件在对话框管理器知道的键盘快捷键上激活。)此问题的规范解决方案是在 100
开始对控件标识符进行编号(我相信Visual Studio 对此负责,但我不确定)。
【讨论】:
#define
不会创建常量。当我写foo(ID_BUTTON);
时,没有常数。只是一个预处理器宏扩展和一个int
文字。
对;我的意思是以简单的方式区分变量和常量。我会在下一段中讨论预处理器的替换。以上是关于是否可以使用方法返回使用#define 创建的变量?的主要内容,如果未能解决你的问题,请参考以下文章