#define vs const in Objective-C


81

我是Objective-C的新手,并且关于const和预处理指令还有一些问题#define

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

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

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

Answers:


107

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

为什么呢 这不是真的:

#define MY_INT_CONSTANT ((int) 12345)

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

是。 #define定义一个宏,即使在编译开始之前,该宏也会被替换。 const仅修改变量,以便在尝试更改变量时编译器将标记错误。在某些情况下,您可以使用a,#define但不能使用a const(尽管我正在努力使用最新的clang查找一个)。从理论上讲,const占用可执行文件中的空间并需要引用内存,但实际上这并不重要,编译器可以对其进行优化。

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

只是想到了可以使用#define但不能使用的上下文const。如果您有一个常量要在大量.c文件中使用,则#define只需将其放在标头中即可。使用a,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

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

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”无法完成
shortstuffsushi

我认为#define比const占用可执行文件更多的空间。const存储一次,但是每次使用#define时都会相乘,因为它只是文本替换。但是,由于差异不大,因此我变得不必要。
Ryan Ballantyne

@RyanBallantyne我认为您可能适合字符串常量之类的东西,但不适用于整数常量,因为即使将常量存储在一个位置,要访问它,您也需要它的地址至少与一样大int。但是,如果它在现代编译器中根本没有影响,我会感到非常惊讶。
JeremyP 2015年

16

从C编码器:

Aconst只是变量,其内容无法更改。

#define name value,然而,就是替换的所有实例预处理命令namevalue

例如,如果您使用#define defTest 5,则defTest代码中的所有实例将5在编译时替换为。


11

重要的是要理解#define和const指令之间的区别,这并不意味着相同。

const

const用于根据所询问的类型生成一个对象,该对象一旦初始化便将保持不变。这意味着它是程序存储器中的一个对象,可以用作只读对象。每次启动程序时都会生成该对象。

#define

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

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


7

除了其他人的评论外,#define众所周知,使用错误很难调试,因为预处理器会在编译器之前掌握它们。


3

由于不赞成使用预处理程序指令,因此建议使用const。您无法使用预处理程序指定类型,因为在编译之前已解析了预处理程序指令。可以,但是类似:

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

并用作

DEFINE_INT(x,42) 

编译器将其视为

const int x = 42;

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

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

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

通常,使用const而不是预处理器指令可以帮助调试,但在这种情况下并没有那么多(但仍然可以)。

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

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


为什么只键入const ...in而不使用宏?
Ed Heal 2012年

1
@EdHeal不要。我只是说您可以回应“我发现无法使用#define定义常量的类型,为什么呢?”
Luchian Grigore 2012年

1
> pre-processor directives are frowned upon[需要引用]
Ben Leggiero 2015年

我认为您可以使用如下类型:#define myValue((double)2)。据我了解,预处理器将用define语句后的内容(包括类型信息)替换“ myValue”。
vomako

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来执行我所显示的内容,并使用常量来声明需要在其上指定类型的常量变量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.