命名:为什么命名常量在C++/Java中都是大写的?

Mne*_*nth 33 c++ java naming-conventions

我知道,对于C++和Java来说,它是一个完善的命名约定,常量应该全部写成大写,并用下划线来分隔单词.像这样(Java示例):

public final static Color BACKGROUND_COLOR = Color.WHITE;
public final static Color TEXT_COLOR = Color.BLACK;
Run Code Online (Sandbox Code Playgroud)

这个命名约定很容易理解和遵循,但我问自己,为什么选择这个命名约定而不是变量的常规命名约定:

public final static Color backgroundColor = COLOR.WHITE;
public final static Color textColor = COLOR.BLACK;
Run Code Online (Sandbox Code Playgroud)

似乎没有必要改变常量的外观.如果我们想为它们分配一个值,编译器将会阻止它.实际上它会产生问题,如果以后将常量变为适当的变量(因为颜色可以配置为例如).

那么将命名常量全部写成大写的最终原因是什么?历史原因?

Dav*_*eas 31

我认为这不是技术问题,而是心理问题.命名约定不是由编译器处理(计算机并不真正关注名称),而是为浏览代码的程序员提供尽可能多的信息,只需要尽可能少的努力.

使用不同的命名约定清楚地告诉读者,您正在阅读的内容是在编译时固定的内容,您无需通过代码来确定值的位置和方式.

  • 它是否真的必须在编译时修复?运行时常量怎么样,例如程序开始执行的时间?固定集合怎么样,编译器无法理解但仍然有效. (5认同)
  • 使用类型的枚举范围是一个更清晰的常量指示,而不是全大写,因为它不仅表明它是一个常数,而且还表示它是什么样的常量.全大写是针对语言外部的符号,但Java和C#没有预编译器.此外,所有鞋面都难以阅读和丑陋. (3认同)
  • @Jon Skeet:这是一个很好的观点:如何应对边界.常数的定义是什么?在这里,您正在使用您使用的语言.对我来说,它们应该是大写的,因为它们是常量...不管它们_are_常量的语言/编译器的限制. (2认同)

Jon*_*eet 17

如果我知道某些东西是常数,我可以多次引用它并知道它不会改变.换句话说,我知道:

Color black = Colors.BLACK;
foo(black);
foo(black);
Run Code Online (Sandbox Code Playgroud)

是相同的:

foo(Colors.BLACK);
foo(Colors.BLACK);
Run Code Online (Sandbox Code Playgroud)

有时候知道这很有用.我个人更喜欢.NET命名约定,即使用Pascal case作为常量(和方法):

Foo(Colors.Black);
Foo(Colors.Black);
Run Code Online (Sandbox Code Playgroud)

我不是一个狡猾的案例的忠实粉丝......但我确实认为常数显然是常数.

  • 我的回答并没有谈到为什么恒常有用 - 它讨论了为什么*了解*关于恒定是有用的.这就是命名的来源. (8认同)
  • 问题是:为什么使用不同的命名方案来表示持久性?不是为什么恒常有用. (3认同)
  • 我也希望自己的代码不对我大喊大叫,因此倾向于使用PascalCase-它更具可读性!!!!!!! 11 (2认同)

unw*_*ind 16

我可以想象,最初,在C日,人们将使用预处理器象征性地实现"常量":

typedef unsigned int Color;
#define BACKGROUND_COLOR 0xffffff
Run Code Online (Sandbox Code Playgroud)

这样的"常量"只是美化文字,因此它们不像变量那样表现.例如,你不能接受这种"常数"的地址:

Color *p = &BACKGROUND_COLOR; // Breaks!
Run Code Online (Sandbox Code Playgroud)

出于这个原因,让它们"脱颖而出"是有道理的,因为它们不仅仅是"你无法改变的变量".

  • 不要忘记可能导致令人讨厌的副作用的#define宏.将它们全部大写为"这里是龙!"提供了视觉提示. (7认同)
  • 但是现在不是IDE的工作吗?让他们脱颖而出? (2认同)
  • 即使在今天,并非所有人都使用IDE.在vi中,我仍然花费了一小部分时间(约10%). (2认同)

Tim*_*sch 12

我相信C++这是一个从使用预处理器到#define常量值的过程.那时候,我们这样做是为了避免让预处理器践踏你的源代码,因为C函数和变量名的通常约定会使它们混合大小写或小写.

从C++的角度来看,我会说让你的常量全部大写是一个坏主意.由于这个原因,我不得不调试多个构建问题 - 请记住,C++预处理器对名称空间和命名范围一无所知,并且很乐意替换它认为合适的内容,即使它是不合适的.

  • 这正是我要说的.今天,在C++中,使用ALL_UPPER_CASE作为常量是一种反成语,因为预处理程序可能会使用从您没想到的某个地方(例如供应商的C OS头文件)中拾取的某些宏来破坏常量. (5认同)
  • 这就是Google在命名约定中使用`kConstantName`的原因.有点保留旧样式的替代方案是k_CONSTANT_NAME. (2认同)

Hit*_*age 6

不要仅仅因为常量曾经是宏而将ALL_CAPS用于常量。

《C ++核心指南》中的这句话引述了全部内容。


dea*_*mon 5

我认为大写常量是 C 的糟糕遗产。背后的逻辑与使用下划线作为私有成员前缀时的逻辑相同。这是技术性的东西,已经用 Java 关键字表达了,例如,private或者,在常量的情况下,static final


t0r*_*0rx 5

在C(然后是C++)中,使用预处理器#define指令定义的符号全部用大写字母写成,向开发人员发出一个响亮的信号,即代码不像它看起来那样并且不被视为普通符号.常量最初并不存在于K&R C中(虽然const后来从C++中恢复),因此开发人员使用了它#define,因此使用了大写字母.

出于某种原因,这被扭曲成Java,因为"常数是上限",因此当前误导(IMO)惯例.


Shi*_*hah 5

实际上,大多数 C++ 命名指南(包括 ISO、Boost、Sutter & Stroustrup 和 Google)强烈反对使用全部大写的命名常量。这是因为宏也使用全部大写,并且它们可能散布在头文件中,可能会产生奇怪的行为。无论如何,人们仍然使用全部大写,因为他们从旧的 C/K&R 或旧的遗留代码中学习。然而,在现代 C++ 新代码中,您应该避免对除宏之外的任何内容使用全部大写。

我对为什么全部大写存在的宠物理论是,在非常旧的机器上,代码是使用数字键盘直接在机器代码中输入的。当汇编语言出现时,它只使用全部大写,因为当时的键盘尚未标准化,并且某些键盘受到限制,例如,使用与功能手机相同的数字键盘来输入字母。这后来被延续到许多早期语言,比如 BASIC,它涵盖了一切。当实际的终端可用并且键盘开始标准化时,人们开始毫无保留地使用混合大小写,并且所有大写字母都被保留给那些很少出现的东西,例如与函数和变量相比的常量。

大多数 C++ 指南现在都同意使用“k”作为常量的前缀,后跟带有下划线或驼峰命名法的名称。我个人更喜欢 kCameCase,因为它可以轻松区分使用下划线命名的变量。

const float kFixedRadius = 3.141;
Run Code Online (Sandbox Code Playgroud)


Grz*_*lik 1

也许你是对的。计算机和编译器(尤其是)没有今天那么快。

Joel Spolsky 在他的一篇文章中提到,新版本 Turbo Pascal 的编译时间给他留下了深刻的印象。

我记得在 PC XT 10MHz 上的 Turbo Pascal 5.0 中编译不太大的程序 (10-20KLOC) 需要大约 20 分钟......

我想等待编译来检测错误是不可接受的。

这样的约定有助于避免在损坏的编译过程中出现错误和浪费时间。