【问题标题】:What is the difference between #define and creating a normal type?#define 和创建普通类型有什么区别?
【发布时间】:2013-11-14 17:13:40
【问题描述】:

在 C/C++ 中,使用 #define [和 #ifndef #endif] 创建值有什么区别,而您也可以轻松地使用 intstd::string [C++] 来创建值?

#ifndef MYVAL
#define MYVAL(500)
#endif

//C++

cout << MYVAL << endl;

//C

printf(MYVAL);

//C++

int MYVAL = 500;
cout << MYVAL << endl;

//C
int MYVAL = 500;
printf(MYVAL);

【问题讨论】:

  • 请注意,C 的两个代码 sn-ps 都无法编译。
  • MYVAL 定义中的括号没有用。
  • 我认为你的意思是#define MYVAL(500)有两个问题,首先它有'500'作为宏参数,这是非法的,如果名称是数字,它应该已经使用像 #define MYVAL(a500) 这样允许的东西作为前缀就可以了,就像其他地方的命名约定一样。其次,由于宏的声明没有任何内容而且它是单个参数,因此它基本上什么都不做,假设您以正确的方式使用它:您不能只在某个地方使用 MYVAL,您还必须在其中放置一个参数(即,MYVAL(some_param)),但替换为空值!

标签: c++ c if-statement c-preprocessor


【解决方案1】:

你的假设是错误的。 #define 不会创建“值”,它会在您的源代码中创建替换文本。它基本上与C或C++无关。

【讨论】:

    【解决方案2】:

    在我进入历史之前,这里先简要了解一下两者之间的区别。

    变量就是变量。它们在编译的程序中占用空间,除非你用const 标记它们(这是比宏晚得多的开发),它们是可变的。

    另一方面,宏是预处理。编译器永远不会看到宏。相反,宏是在编译之前处理的。预编译器遍历代码,找到每个宏,并用宏文本逐字替换它。这可能非常强大,有些有用,而且相当危险(因为它正在修改代码并且在这样做时从不进行任何检查)。

    此外,可以在命令行上设置宏。您可以在编译时定义任意数量的东西,如果您的代码检查该宏,它的行为可能会有所不同。

    宏早在 C++ 之前就已存在。它们对很多事情都有用:

    • 您可以很容易地使用它们来表示常量表达式。它们可以节省空间,因为它们不需要任何变量(尽管常量表达式仍然需要在某处编译),并且它们存在于 const 说明符之前,因此它们是维护常量“变量”的简单方法 -预编译器会将 MYVAR 的所有实例替换为 500。
    • 您可以使用它们执行各种功能。实际上,我自己从来没有做过,因为收益似乎永远不会超过风险。没有仔细构造的宏函数很容易破坏你的编译。但是我使用了一些预定义的宏函数。
    • #define 宏仍然用于许多事情
      • 包括保护(头文件通常在顶部定义了一个宏,并检查它是否已定义以确保它们不会再次添加它),
      • C 中的 TRUE 和 FALSE,
      • 设置调试模式,以便代码在调试和发布时表现不同。作为一个简单的示例,断言是在存在 DEBUG 宏时行为不同的函数。 (如果不存在,则返回完全空的代码。)

    在您只是使用宏来表示常量表达式的有限情况下,您是对的 - 不再需要它们。

    【讨论】:

    • 应该教导学习 C 或 C++ 的人预处理是与后续语义操作分开的阶段,而不是“编译器永远不会看到宏”。预处理是语言翻译的一部分(例如,根据 C 2011 5.1.1.2),它可以集成到编译器中(就像 GCC 一样)。这可能会产生诸如智能错误消息(将预处理效果与其他信息交织在一起)或由于源代码中较早阶段预处理错误(例如@ 987654323@).
    【解决方案3】:

    不同之处在于,使用宏 (#),预处理器会在该符号上进行搜索和替换。替换没有类型检查。

    当你创建一个变量时,它是有类型的,编译器会在你使用它的地方进行类型检查。

    C/C++ 编译器通常被认为是 2-pass 编译器。第一遍是对宏进行搜索和替换的预处理器。第二遍是创建声明变量的实际编译。

    宏通常用于创建更复杂的表达式,因此代码不必重复多次,因此语法更紧凑。它们很有用,但由于它们的“盲目”搜索和替换性质,它们也更危险。此外,您无法使用调试器单步执行宏,因此更难排除故障。

    此外,宏不遵守任何范围规则。 #define MYVAL(500) 将用500 替换MYVAL,即使它出现在函数、全局范围、类声明等中,所以你必须更加小心。

    【讨论】:

    • 实际上,预处理指令的宏扩展和执行是 C 2011 程序翻译的八个阶段之一(根据第 5.1.1.2 节)。它们不一定在单独的通道中执行。例如,GCC 一次性完成预处理和后续编译。
    • 感谢@Eric Postpischil。我试图让预期的问题保持简单。
    【解决方案4】:

    当你#define某事时,只要在你的代码中找到它就会被盲目替换:

    #define the_answer 42
    /// ...
    
    int the_answer = /* oops! */
    

    【讨论】:

      【解决方案5】:

      您不应该使用#defines 有几个重要原因。对于您的问题,我会说,#define 是纯文本替换,您不能限制宏的范围。即,您不能指定访问说明符或将其绑定到命名空间,因此一旦定义了宏,您就可以在包含定义的文件中的任何位置使用它们。

      使用 'const' 变量,您可以将它们绑定在一个范围内

      这些可能会有所帮助:http://www.parashift.com/c++-faq/const-vs-define.html

      http://www.parashift.com/c++-faq/preprocessor-is-evil.html

      【讨论】:

        【解决方案6】:

        有很大的不同:

        a)#define MYVAL 500

        这将创建一个宏。它在源代码中的每一次出现都将被预处理器替换为其原始值。它完全忽略了作用域,你不能改变它的值

        b)int MYVAL = 500;

        这是一个遵守范围规则的常规变量,即。 e.在函数内部声明时,在函数外部看不到,可以在另一个函数中隐藏,等等...

        另一方面,变量不能用于预处理条件(#if#endif 块)

        最后一个例子:

        #define MYVAL 500
        
        int main() {
            int MYVAL = 10; // illegal, gets preprocessed as int 500 = 10;
        }
        

        与变量相同:

        int MYVAL = 500
        
        int main() {
            int MYVAL = 10; // legal, MYVAL now references local variable, ::MYVAL is the global variable
        }
        

        【讨论】:

          猜你喜欢
          • 2011-02-25
          • 2022-08-19
          • 1970-01-01
          • 2023-01-07
          • 2020-05-23
          • 2020-09-22
          • 1970-01-01
          • 2015-11-18
          • 1970-01-01
          相关资源
          最近更新 更多