为什么在编程中要使用常量?

39

我最近重新学习了一些C语言,使用了Ivor Horton的《Beginning C》书籍。我遇到了关于声明常量的问题,似乎在同一句中与变量混淆了。

为了澄清,在C语言中指定常量和变量之间的区别是什么?实际上,你什么时候需要使用常量而不是变量呢?我知道有人说在程序执行期间信息不会改变时使用常量,但我真的想不出何时不能使用变量代替常量。


固定长度可以节省内存,最坏情况下需要复制到新数组。 - Niklas Rosencrantz
这个问题只需要一个反例:为什么要把PI定义成变量? - Hans Passant
同意,一个"3"的值非常可能接近黑洞的地平线。这也需要重新定义bool类型,必须添加“文件无法恢复丢失”的内容。 - Hans Passant
3
@开发者艺术:π是一个抽象的数学常数,独立于物理空间,就像其他数学常数一样。 - David R Tribble
@Loadmaster:这将意味着宇宙的物理属性不随时间或位置而改变。恕我直言,您不能完全确定这一点。异常和悖论可能存在。人类只看到了宇宙的一个非常小的角落。更不用说平行维度和其他事物了。 - user151323
显示剩余4条评论
10个回答

48

变量,如名称所示,会随着时间变化而变化。如果它不变,则不存在“损失”。当您告诉编译器该值不会更改时,编译器可以进行大量优化,例如直接将值内联并且不在栈上分配任何常量的空间。

但是,您不能总是指望编译器足够聪明,能够正确确定一旦设置后一个值是否会更改。在任何编译器无法百分之百确定时,编译器都会以安全为先,并假设其可能会更改。这可能导致各种性能影响,例如避免内联、不优化某些循环、创建不太支持并行处理的目标代码等。

因此,由于可读性也很重要,您应该尽可能使用显式常量,留下变量处理实际可能会更改的事物。

至于为什么使用常量而不是文字数字:

1)它使代码更易读。每个人都知道3.14是什么(希望如此),但并不是每个人都知道3.07是宾夕法尼亚州的所得税率。这是领域特定知识的例子,未来维护您的代码的每个人(例如,税务软件)都可能不知道它。

2)在进行更改时可以节省工作量。如果将来税率更改,去更改每个3.07为3.18将会很烦人。您总是要尽量减少更改,并理想情况下进行单次更改。您必须进行的并发更改越多,就越容易忘记某些事情,导致错误。

3)您可以避免风险错误。想象一下有两个州的所得税率都为3.05,然后其中一个变成了3.18,而另一个仍然是3.07。通过只是进行替换,您可能会遇到严重错误。当然,许多整数或字符串常量值比“3.07”更常见。例如,数字7可以表示一周中的天数和其他内容。在大型程序中,很难确定每个文字值的含义。

4) 对于字符串文本,通常会使用符号名称来允许字符串池在支持多种语言的情况下快速更改。

除了变量和“常量变量”之外,还有一些具有枚举的语言。枚举实际上允许您为一小组常量(例如返回值)定义类型,因此使用它们将提供类型安全性。

例如,如果我有一个星期几和月份的枚举,当我将月份赋值给星期几时,系统会警告我。如果我只使用整数常量,则在将第3天分配给第3个月时将没有警告。您始终希望拥有类型安全性,这将提高可读性。枚举也更适合定义顺序。想象一下,如果您有星期几的常量,现在您想让一周从星期一开始,而不是星期日。


5
OP并不是在询问字面常量,而是在问为什么要使用常量,如果事物不会改变的话,为什么不把所有东西都用变量呢?这好像不会用完... - Brian Postow
4
我认为我的回答的第一个段落已经回答了这个问题:如果一个变量不随时间改变,那么就没有必要使用它。但我会进一步澄清这个问题。 - Uri
我还要补充一点:5)类型安全。 - matias
我同意Brian的观点,信息太多了。但是,标题会让人们对这里有什么期待呢? - James Morris
感谢所有回复我的人,希望我没有引发争议。我觉得我在编程中有点懒惰,大多数情况下都使用变量。现在回到C语言,经过长时间的Python编程(那里也从未使用常量),了解为什么我们要这样做是很好的。现在正在重新学习如何指定常量。再次感谢。 - Adam N
2
3.14 明显是 ((e*phi)^(phi/2)-3) << 1 - Mateen Ulhaq

20

使用常量更多是一种防御性编程的方式,以保护自己免受在凌晨2点或在喝咖啡之前编码时意外更改代码中某个值的影响。

从技术上讲,你也可以使用变量。


3
当然,谢谢。这就是在半夜回答问题时会出现的情况。 :) - user151323
10
别忘了,睡眠 也是一种防御式编程策略。 - Jackson
你是指像这样吗? ;)startBackgroundProcess(); sleep(1000); // 确保进程已经启动完成 useBackgroundProcesses(); - duckbrain

14

常量相比变量有几个优势。

常量提供了某种程度的保证,即代码无法更改底层值。这对于较小的项目并不重要,但在由多个作者编写的多个组件组成的大型项目中很重要。

常量还为编译器提供了强烈的优化提示。由于编译器知道该值无法更改,因此它不需要从内存中加载该值,并且可以将代码优化为仅适用于常量的确切值(例如,如果const是2的幂,则编译器可以使用移位进行乘除运算)。

常量也是固有的静态的——您可以在头文件中声明常量及其值,并且无需担心定义它的确切位置。


2
这样的保证可以使后续的调试和维护更加容易 - 如果某个东西是一个变量,你经常会发现自己在搜索代码中任何改变它的地方;如果它是一个常量,你可以避免这种情况。 - caf

10

首先是性能优化。

更重要的是,这是为人类读者而设计的。请记住,你的目标受众不仅仅是编译器。在代码中表达自己,避免使用注释,可以帮助你更好地表达。

const int spaceTimeDimensions = 4;

if(gpsSattelitesAvailable >= spaceTimeDimensions)
  Good();

3
OP实际上并不是在询问常量与字面量的区别,而是在询问常量与变量的区别。 - Brian Postow
尽管如此,它仍然是一个可读性工具。 - Pavel Radzivilovsky

4

对于像C这样的低级语言,常量允许进行多个编译优化。

对于一般的编程语言来说,你并不真正需要它们。高级动态语言,比如Ruby和JavaScript,没有常量(或者至少不是真正的常量)。相反,变量被使用,就像你所建议的那样。


3

常量是当您只想共享内存且其不会改变时使用的。


5
当你想要分享记忆时,你会进行心灵融合。我的思维与你的思维交汇...... - user151323
4
头脑融合?那是像奶酪一样浇在面包上吗? - James Morris
那么,总体而言,与使用变量相比,它会提高性能吗? - Shivashriganesh Mahato

2

const关键字常用于函数参数,特别是指针,以表明指针所指向的内存不会被函数修改。例如,看看strcpy的声明:

char *strcpy(char *dest, const char *src);

否则,例如,像这样的声明:
const int my_magic_no = 54321;

可能更喜欢使用:
#define MY_MAGIC_NO 54321

为了类型安全的原因。

哦,我突然意识到我并没有真正回答为什么要使用常量而不是变量的问题。 - James Morris
我认为OP不是在问参数,而是在问局部变量... - Brian Postow
谢谢Brian指出这一点。就好像我还没有注意到一样;-| - James Morris

1

这是一种非常简单的捕获某些类别错误的方法。如果你声明一个变量为const,并且意外地尝试修改它,编译器会提示你。


1

常量在声明和初始化变量方面非常必要,无论是在循环开始时,还是在if-else语句中检查条件等任何目的。

如需更多参考,请随意阅读以下文章之一:


那个网站适合初学者。 - yogi

0

不使用const可能意味着团队项目中的某个人可以声明int FORTY_TWO = 42,并使其在另一个团队成员的其他地方等于FORTY_TWO = 41。因此,世界末日发生了,你也失去了生命的答案。但是,使用const,这些都永远不会发生。此外,const存储在内存中的其他位置,与普通变量的存储位置相比更加高效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接