【问题标题】:#define vs const in Objective-CObjective-C 中的#define vs const
【发布时间】:2012-06-24 13:45:03
【问题描述】:

我是 Objective-C 的新手,我有几个关于 const 和预处理指令 #define 的问题。

首先,我发现使用#define 定义常量的类型是不可能的。这是为什么呢?

其次,使用其中一个比另一个有什么优势吗?

最后,哪种方式更高效和/或更安全?

【问题讨论】:

    标签: objective-c constants c-preprocessor


    【解决方案1】:

    了解#define 和 const 指令之间的区别很重要,它们并不意味着相同的事情。

    const

    const 用于从请求的类型生成一个对象,一旦初始化,该对象将是常量。这意味着它是程序内存中的一个对象,可以作为只读的。 每次启动程序时都会生成该对象。

    #define

    #define 用于简化代码的可读性和未来的修改。使用定义时,您只需要在名称后面屏蔽一个值。因此,在使用矩形时,您可以使用相应的值定义宽度和高度。然后在代码中,它会更容易阅读,因为将有名称而不是数字。

    如果稍后您决定更改宽度值,您只需在定义中更改它,而不是在整个文件中进行无聊且危险的查找/替换。 编译时,预处理器会将所有定义的名称替换为代码中的值。因此,使用它们不会浪费时间。

    【讨论】:

      【解决方案2】:

      来自 C 程序员:

      const 只是一个变量,其内容无法更改。

      然而,#define name value 是一个预处理器命令,它将所有 name 实例替换为 value

      例如,如果您#define defTest 5,那么您的代码中所有defTest 的实例都将在您编译时替换为5

      【讨论】:

        【解决方案3】:

        我以前使用过#define 来帮助从一种方法中创建更多方法,例如我有类似的方法。

         // This method takes up to 4 numbers, we don't care what the method does with these numbers.
         void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;
        

        但我也有什么方法只需要 3 个数字和 2 个数字,所以我将使用 #define 来使用相同的方法,而不是编写两个新方法,就像这样。

         #define doCalculationWithFourNumbers(num1, num2, num3, num4) \
                 doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4))
        
         #define doCalculationWithThreeNumbers(num1, num2, num3) \
                 doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil)
        
         #define doCalculationWithTwoNumbers(num1, num2) \
                 doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)
        

        我认为这是一件很酷的事情,我知道您可以直接使用该方法并将 nil 放在您不想要的空间中,但是如果您正在构建一个库,它非常有用。也是这样的

             NSLocalizedString(<#key#>, <#comment#>)
             NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
             NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)
        

        完成了。

        而我不相信你可以用常量做到这一点。但是常量确实比#define 有好处,就像你不能用#define 指定一个类型,因为它是一个在编译之前解析的预处理器指令,如果你在#define 中遇到错误,那么它们就更难调试了常数。两者都有优点和缺点,但我想说这完全取决于你决定使用哪个程序员。我已经用它们编写了一个库,使用#define 来执行我所展示的操作,并使用常量来声明我需要指定类型的常量变量。

        【讨论】:

          【解决方案4】:

          首先,我发现用#define定义常量的类型是不可能的,这是为什么呢?

          为什么是什么?这不是真的:

          #define MY_INT_CONSTANT ((int) 12345)
          

          其次,使用其中一个比另一个有什么优势吗?

          是的。 #define 定义了一个宏,它甚至在编译开始之前就被替换了。 const 只是修改一个变量,以便在您尝试更改它时编译器会标记错误。在某些情况下,您可以使用#define,但不能使用const(尽管我正在努力寻找一个使用最新的clang)。理论上,const 会占用可执行文件中的空间并需要对内存的引用,但实际上这无关紧要,并且可能会被编译器优化掉。

          consts 比#defines 对编译器和调试器更友好。在大多数情况下,这是您在决定使用哪一个时应该考虑的最重要的一点。

          刚刚想到一个可以使用#define 但不能使用const 的上下文。如果你有一个常量要在很多.c 文件中使用,使用#define 你只需将它放在标题中。使用const,您必须在 C 文件中有一个定义,并且

          // in a C file
          const int MY_INT_CONST = 12345;
          
          // in a header
          extern const int MY_INT_CONST;
          

          在标题中。 MY_INT_CONST 不能用作任何 C 文件中的静态或全局范围数组的大小,但定义它的文件除外。

          但是,对于整数常量,您可以使用enum。事实上,这就是苹果几乎一成不变的做法。这具有#defines 和consts 的所有优点,但仅适用于整数常量。

          // In a header
          enum
          {
              MY_INT_CONST = 12345,
          };
          

          最后,哪种方式更高效和/或更安全?

          #define 在理论上更有效,尽管正如我所说,现代编译器可能确保几乎没有区别。 #define 更安全,因为尝试分配给它总是编译器错误

          #define FOO 5
          
          // ....
          
          FOO = 6;   // Always a syntax error
          

          consts 可以被欺骗,尽管编译器可能会发出警告:

          const int FOO = 5;
          
          // ...
          
          (int) FOO = 6;     // Can make this compile
          

          根据平台的不同,如果常量放置在只读段中并且根据 C 标准它是官方未定义的行为,则赋值可能在运行时仍然失败。

          就个人而言,对于整数常量,我总是将enums 用于其他类型的常量,除非我有充分的理由不使用,否则我使用const

          【讨论】:

          • 我知道它很旧,但是您不能使用可以使用定义的 const 的一个实例是“#define MY_NSNUM_CONSTANT @5”,它无法使用“NSNumber * const MY_NSNUM_CONSTANT = @5"
          • 我认为#define 在可执行文件中比 const 占用更多空间。一个 const 存储一次,但每次使用它时都会乘以 #define,因为它只是文本替换。但是由于差异微不足道,因此我不必要地迂腐。
          • @RyanBallantyne 我认为您可能适合字符串常量之类的东西,但不适用于整数常量,因为即使您将常量存储在一个地方,要访问它,您也需要它的地址,该地址至少要大作为int。但是,如果它在现代编译器中产生任何影响,我会感到非常惊讶。
          【解决方案5】:

          由于预处理器指令不受欢迎,我建议使用const。您不能使用预处理器指定类型,因为预处理器指令在编译之前已解析。好吧,你可以,但类似:

          #define DEFINE_INT(name,value) const int name = value;
          

          并将其用作

          DEFINE_INT(x,42) 
          

          编译器会将其视为

          const int x = 42;
          

          首先,我发现不能用#define定义常量的类型,这是为什么呢?

          你可以,看看我的第一个sn-p。

          其次,使用其中一个比另一个有什么优势吗?

          通常使用 const 而不是预处理器指令有助于调试,但在这种情况下作用不大(但仍然如此)。

          最后,哪种方式更高效和/或更安全?

          两者都一样有效。我想说宏可能可能更安全,因为它不能在运行时更改,而变量可以。

          【讨论】:

          • 为什么只输入const ... 而不是使用宏?
          • @EdHeal 不要。我只是说您可以回应“我发现无法使用#define定义常量的类型,为什么会这样?”
          • > pre-processor directives are frowned upon [需要引用]
          • 我认为你可以使用这样的类型:#define myValue ( (double) 2 )。据我了解,预处理器只会用定义语句中的“myValue”替换它之后的内容,包括类型信息。
          【解决方案6】:

          除了其他人的 cmets,使用 #define 的错误是出了名的难以调试,因为预处理器会在编译器之前获取它们。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-13
            • 2011-03-12
            • 1970-01-01
            • 2021-02-14
            • 1970-01-01
            • 2012-08-20
            • 2014-03-23
            • 2014-02-12
            相关资源
            最近更新 更多