82

我是 Objective-C 的新手,我有一些关于constpreprocessing 指令的问题#define

首先,我发现无法使用#define. 这是为什么?

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

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

4

6 回答 6

107

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

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

#define MY_INT_CONSTANT ((int) 12345)

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

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

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

只是想到了一个可以使用#define但不能使用的上下文const。如果您有一个要在大量.c文件中使用的常量,#define只需将其粘贴在标题中即可。使用 aconst你必须在 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除非我有充分的理由不使用。

于 2012-06-22T10:11:02.260 回答
17

来自 C 编码器:

Aconst只是一个变量,其内容不能更改。

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

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

于 2012-06-22T09:09:43.213 回答
11

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

const

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

#define

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

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

于 2012-06-22T09:25:20.903 回答
7

除了其他人的评论之外,#define由于预处理器在编译器之前获取它们,因此使用错误是非常难以调试的。

于 2012-06-22T09:14:40.623 回答
3

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

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

并将其用作

DEFINE_INT(x,42) 

编译器会将其视为

const int x = 42;

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

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

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

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

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

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

于 2012-06-22T09:06:23.610 回答
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 来执行我所展示的操作,并使用常量来声明我需要指定类型的常量变量。

于 2012-06-22T10:27:49.093 回答