在Objective-C中#define vs const

时间:2012-06-22 09:02:42

标签: objective-c const c-preprocessor

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

首先,我发现使用#define无法定义常量的类型。那是为什么?

第二,使用其中一个优于另一个是否有任何好处?

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

6 个答案:

答案 0 :(得分:106)

  

首先,我发现使用#define无法定义常量的类型,为什么会这样?

为什么是什么?事实并非如此:

#define MY_INT_CONSTANT ((int) 12345)
  

第二,使用其中一个优于另一个是否有任何好处?

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

const#define更适合编译器和调试器。在大多数情况下,这是在决定使用哪一个时应该考虑的最重要的一点。

只考虑了可以使用#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。事实上,这几乎是苹果所做的。这具有#defineconst的所有优点,但仅适用于整数常量。

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

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

#define在理论上更有效,但正如我所说,现代编译器可能确保没有什么区别。 #define更安全,因为尝试分配它始终是编译器错误

#define FOO 5

// ....

FOO = 6;   // Always a syntax error
虽然编译器可能会发出警告,但可以欺骗

const进行分配:

const int FOO = 5;

// ...

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

根据平台的不同,如果常量放在只读段中,并且根据C标准,它的正式未定义行为,则在运行时分配可能仍会失败。

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

答案 1 :(得分:16)

来自C编码员:

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

但是,

#define name value是一个预处理程序命令,用name替换value的所有实例。

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

答案 2 :(得分:10)

理解#define和const指令之间的区别非常重要。这些指令并不意味着相同的事情。

const

const用于从被询问的类型生成一个对象,该对象在初始化后将是常量。这意味着它是程序存储器中的一个对象,可以作为readonly使用。 每次启动程序时都会生成该对象。

#define

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

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

答案 3 :(得分:7)

除了其他人的评论之外,使用#define的错误也很难调试,因为预处理器会在编译器之前获取它们。

答案 4 :(得分:2)

由于预处理器指令不受欢迎,我建议使用const。您无法使用预处理器指定类型,因为在编译之前会解析预处理器指令。嗯,你可以,但是像:

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

并将其用作

DEFINE_INT(x,42) 

将被编译器视为

const int x = 42;
  

首先,我发现使用#define无法定义常量的类型,为什么会这样?

你可以,看看我的第一个片段。

  

第二,使用其中一个优于另一个是否有任何好处?

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

  

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

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

答案 5 :(得分:1)

之前我曾使用#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来做我已经显示的内容和常量来声明我需要指定类型的常量变量。