我知道 , -1
, 0
,1
和2
是幻数规则的例外。但是我想知道当它们是浮动时是否也是如此。我是否必须为它们初始化最终变量,或者我可以直接在我的程序中使用它们。
我在课堂上使用它作为百分比。如果输入小于 0.0 或大于 1.0,那么我希望它自动将百分比设置为零。所以如果(0.0 <= 输入 && 输入 <= 1.0)。
谢谢
我知道 , -1
, 0
,1
和2
是幻数规则的例外。但是我想知道当它们是浮动时是否也是如此。我是否必须为它们初始化最终变量,或者我可以直接在我的程序中使用它们。
我在课堂上使用它作为百分比。如果输入小于 0.0 或大于 1.0,那么我希望它自动将百分比设置为零。所以如果(0.0 <= 输入 && 输入 <= 1.0)。
谢谢
这真的取决于上下文。避免幻数的重点是保持代码的可读性。使用您的最佳判断,或向我们提供一些背景信息,以便我们可以使用我们的判断。
幻数是[u]nique values with unexplained meaning or multiple occurrences which could (preferably) be replaced with named constants
。
http://en.wikipedia.org/wiki/Magic_number_(编程)
编辑:何时使用变量名称记录代码与何时仅使用数字是一个备受争议的话题。我的观点是上面链接的 Wiki 文章的作者的观点:如果含义不是很明显并且在您的代码中多次出现,请使用命名常量。如果它只出现一次,只需注释代码。
如果您对其他人(强烈偏见)的意见感兴趣,请阅读 什么是自文档化代码,它可以取代有良好文档记录的代码吗?
这些数字并不是幻数规则的真正例外。常识规则(只要有“一个”规则),当它没有被简化到教条的水平时,基本上是,“不要在不明确其含义的上下文中使用数字。” 碰巧这四个数字在明显的上下文中非常常用。这并不意味着它们是唯一适用的数字,例如,如果我有:
long kilometersToMeters(int km) { return km * 1000L; }
命名数字确实没有意义:从微小的上下文中可以明显看出它是一个转换因子。另一方面,如果我在一些低级代码中这样做:
sendCommandToDevice(1);
它仍然是错误的,因为那应该是一个常数kResetCommand = 1
或类似的东西。
所以是否0.0
和1.0
应该被一个常数替换完全取决于上下文。
为某物附加一个名称会创建一个身份。鉴于定义
const double Moe = 2.0;
const double Joe = 2.0;
...
double Larry = Moe;
double Harry = Moe;
double Garry = Joe;
Moe 和 Joe 的符号使用表明 Larry 和 Harry 的默认值彼此相关,而 Garry 的默认值则没有。是否为特定常量定义名称的决定不应取决于该常量的值,而是取决于它是否会非巧合地出现在代码中的多个位置。如果一个人正在与需要向其发送特定字节值以触发重置的远程设备通信,我会考虑:
void ResetDevice()
{
// The 0xF9 command is described in the REMOTE_RESET section of the
// Frobnitz 9000 manual
transmitByte(0xF9);
}
... elsewhere
myDevice.ResetDevice();
...
otherDevice.ResetDevice();
在许多情况下优于
// The 0xF9 command is described in the REMOTE_RESET section of the
// Frobnitz 9000 manual
const int FrobnitzResetCode = 0xF9;
... elsewhere
myDevice.transmitByte(FrobnitzResetCode );
...
otherDevice.transmitByte(FrobnitzResetCode );
值 0xF9 在重置 Frobnitz 9000 设备的上下文之外没有实际意义。除非出于某种原因,外部代码应该更喜欢自己发送必要的值而不是调用 ResetDevice 方法,否则该常量应该对方法之外的任何代码没有任何价值。虽然也许可以使用
void ResetDevice()
{
// The 0xF9 command is described in the REMOTE_RESET section of the
// Frobnitz 9000 manual
int FrobnitzResetCode = 0xF9;
transmitByte(FrobnitzResetCode);
}
在如此狭隘的背景下为事物定义名称真的没有多大意义。
像 0 和 1 这样的值的唯一“特殊”之处在于,在它们在使用它们的上下文之外没有特定于域的标识的情况下,它们的使用频率明显高于其他常量,例如 23。如果使用的函数要求第一个参数指示附加参数的数量(在 C 中有些常见),最好说:
output_multiple_strings(4, "Bob", Joe, Larry, "Fred"); // There are 4 arguments
...
output_multiple_strings(4, "George", Fred, "James", Lucy); // There are 4 arguments
比 #define NUMBER_OF_STRINGS 4 // 有 4 个参数
output_multiple_strings(NUMBER_OF_STRINGS, "Bob", Joe, Larry, "Fred");
...
output_multiple_strings(NUMBER_OF_STRINGS, "George", Fred, "James", Lucy);
后一个语句意味着传递给第一个方法的值和传递给第二个方法的值之间的联系比传递给第一个方法的值和该方法调用中的任何其他内容之间存在的联系更强。除其他外,如果需要更改其中一个调用以传递 5 个参数,则在第二个代码示例中不清楚应该更改什么以允许这样做。相比之下,在前一个样本中,常数“4”应改为“5”。
通常,每条规则都有例外(这个也有例外)。为这些常量使用一些助记名称是一种风格问题。
例如:
int Rows = 2;
int Cols = 2;
这是一个非常有效的示例,其中使用原始值会产生误导。
幻数的含义从上下文中应该是显而易见的。如果不是 - 给这个东西一个名字。