当前位置:  开发笔记 > 编程语言 > 正文

#define与常量的优缺点?

如何解决《#define与常量的优缺点?》经验,为你挑选了3个好方法。

有人能指出使用#define对比常数的优缺点吗?我的大部分工作都是用C和Objective-C完成的.



1> jamesdlin..:

作为0A0D提到的,还有#defines,enumsconst变量.值得注意的是,const合格变量在C中不被认为是编译时常量,因此在某些情况下不能使用(例如,在声明数组的大小时).

enum但是,常量是编译时常量.对于积分值,IMO通常更喜欢优先enumsconst变量#define.


因此,总结一下,短规则是:对于积分常量,使用匿名枚举.对于其他一切,使用`const`.除了正确的宏或有条件包含的令牌之外,不要使用`#define`.
令我感到震惊的是,唯一的答案是正确地指出了在C中使用`const`的明显缺点(并且,通过扩展,Objective-C;注意这个问题不是关于C++!)没有被修改到顶部.+1,并希望我能更多地给予它.

2> 小智..:

实际上有三种方法来定义这些常量,

定义

枚举

const变量

在C中,除非另有说明,否则一切都是int.当我有许多相关的整数常量时,我​​更喜欢枚举.当您不关心值是什么时,枚举显然更可取.但即使你确实需要为所有常量指定值,我也喜欢枚举的心理分组.当您拥有类型时,代码文档本身会更好,例如

Error MyFunc();

清楚地返回一组特定的错误代码,而

int MyFunc()

可能会返回Unix errno的#define'd列表中的一个,或者可能是其他东西,或者那些加上一些特殊值 - 谁知道呢?如果您有多组返回代码,此功能使用哪一组?

更具体的枚举类型名称有助于编辑器中的标签工具,greps,调试等.

严格的lint可能会给你一些关于使用枚举作为整数的警告,例如,如果你添加或者它们,或者将枚举传递给int.

const对象不同于枚举或#define,特别是在C中.在ANSI C中,const int占用空间就像常规int一样; 大多数编译器也会生成指向此地址的指针,而不是内联值.因此,我很少在C中使用const int.(C++的语义略有不同,因此选择不同.)

我曾经使用的每个编译器都可以选择在尽可能小的空间中存储枚举.通常它甚至是默认选项.要在使用这样的选项时强制使用更宽的枚举,我通常会抛出一个额外的无符号值:

typedef enum
{
    MyEnumA,
    MyEnumB,

    MyEnumForce16 = 7fff
} MyEnum;

枚举常量(enum)的使用与使用#define的传统符号常量样式相比具有许多优点.这些优点包括较低的维护要求,改进的程序可读性和更好的调试能力.

1)第一个优点是枚举常量由编译器自动生成.相反,符号常量必须由程序员手动赋值.

例如,如果您的程序中可能出现错误代码的枚举常量类型,那么您的枚举定义可能如下所示:

enum Error_Code
{
OUT_OF_MEMORY,
INSUFFICIENT_DISK_SPACE,
LOGIC_ERROR,
FILE_NOT_FOUND
};

在前面的示例中,编译器会自动为OUT_OF_MEMORY分配值0(零),因为它首先出现在定义中.然后编译器继续自动为枚举常量赋值,使INSUFFICIENT_DISK_SPACE等于1,LOGIC_ERROR等于2,FILE_NOT_FOUND等于3,依此类推.如果您通过使用符号常量来接近相同的示例,您的代码将如下所示:

#define OUT_OF_MEMORY 0
#define INSUFFICIENT_DISK_SPACE 1
#define LOGIC_ERROR 2
#define FILE_NOT_FOUND 3

两种方法中的每一种都得到相同的结果:四个常量分配数值来表示错误代码.但是,如果要添加两个常量来表示错误代码DRIVE_NOT_READY,请考虑所需的维护CORRUPT_FILE.使用枚举常量方法,您只需将这两个常量放在枚举定义中的任何位置即可.编译器将为这些常量生成两个唯一值.使用符号常量方法,您必须手动为这些常量分配两个新数字.此外,您需要确保为这些常量指定的数字是唯一的.

2)使用枚举常量方法的另一个好处是,您的程序更具可读性,因此可能需要稍后更新程序的其他人可以更好地理解这些程序.

3)使用枚举常量的第三个好处是某些符号调试器可以打印枚举常量的值.相反,大多数符号调试器无法打印符号常量的值.这对于调试程序来说是一个巨大的帮助,因为如果你的程序在使用枚举的行停止,你可以简单地检查该常量并立即知道它的值.另一方面,由于大多数调试器无法打印#define值,因此您很可能必须通过在头文件中手动查找来搜索该值.

#define语句是预编译器指令.从技术上讲,任何以#开头的行都是预编译器可以执行的操作.预编译器将使用其定义替换定义的标记的所有实例.这样做:

#define DELAY 40
for (i=0;i

与此完全相同(就编译器而言):

for (i=0;i<40;i++) {
    for (j=0;j<40;j++) {
        asm NOP;
    }
}

当编译器生成机器代码时,它将看到数字40并使用立即寻址模式以便与累加器进行比较.数字40将在您引用时多次存储在代码中.在这种情况下,它是两次.这是CodeWarrior Ver5生成的程序集:

7:    char i,j;
    8:    for (i=0;i


+1用于列出所有可用选项,但值得扩展的是使用`enum`的好处,以及`const`与`enum`和`#define`相比的缺点.

3> Asher Dunn..:

常量允许您指定数据类型,这通常是一个优势.宏更灵活,因此如果你不小心,可能会让你更麻烦.

最佳实践是尽可能使用常量,并且仅在您确实需要宏时使用#define,而不仅仅是命名的文字值.


-1没有提到C中的`const`不是真(编译时)常量,因此不能用于`case`标签,数组大小,以及需要常量表达式的其他上下文中.有一个原因可以解释为什么`#define`在C语言中如此重要(并且`const`在C++中使用得更频繁),并且对它的掩饰使得这个问题的答案很糟糕.
IMO,最好的选择是实际使用匿名`enum`作为那些整数常量表达式 - 它有点类型,它是作用域,没有名称缩写等,但它也是一个整数常量.对于其他一切(编译时并不重要 - 浮点数,字符串等),`const`很好.另请注意,匿名枚举在ANSI C89中,即使很多人都相信相反(因为匿名结构不存在).
推荐阅读
手机用户2502852037
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有