【问题标题】:Magic Numbers In Arrays? - C++数组中的幻数? - C++
【发布时间】:2011-01-06 13:28:16
【问题描述】:

我是一个相当新的程序员,如果这些信息很容易从那里获得,我深表歉意,我只是还没有找到它。

这是我的问题:

当您使用文字数字访问数组的特定元素时,是否被视为幻数?

例如:

arrayOfNumbers[6] // Is six a magic number in this case?

我问这个问题是因为我的一位教授坚持认为程序中的所有文字数字都是幻数。使用实数访问数组的元素而不是为每个元素使用命名常量对我来说会很好。

谢谢!

【问题讨论】:

  • #define ONE 1 ... i += ONE;
  • 为了避免这种情况,上帝给了我们 i++ :P
  • @Mef: #define TWO 2 ... if (i % TWO) printf("i is odd\n");。教授应该学会不要像那样过度概括。 “所有字面数字都是神奇的数字”作为教授是荒谬的说法。
  • 请不要在 C++ 中#define 常量。请改用const
  • 当然,我们都知道42是唯一的真正的幻数。

标签: c++ magic-numbers


【解决方案1】:

这真的取决于上下文。如果你有这样的代码:

arr[0] = "Long";
arr[1] = "sentence";
arr[2] = "as";
arr[3] = "array.";

...那么 0..3 不被视为幻数。但是,如果您有:

int doStuff() 
{
   return my_global_array[6];
}

...那么 6 绝对是一个神奇的数字。

【讨论】:

    【解决方案2】:

    这很神奇。

    我的意思是,为什么你要访问第 6 个元素?应该应用于该数字的语义是什么?就目前而言,我们所知道的是“第 6 个(从零开始的)数字”。如果我们知道arrayOfNumbers 的声明,我们将进一步知道它的类型(例如intdouble)。

    但如果你说:

    arrayOfNumbers[kDistanceToSaturn]; 
    

    ...现在它对阅读代码的人来说更有意义了。

    一般来说,遍历一个数组,对每个元素执行一些操作,因为人们不知道数组有多长,而且您不能只以硬编码的方式访问它。

    但是,有时数组元素具有特定含义,例如在图形编程中。有时数组总是相同的大小,因为数据需要它(例如某些变换矩阵)。在这些情况下,通过数字访问特定元素可能会也可能不会:领域专家会知道您在做什么,但通才可能不会。给魔法索引号起个名字可以让那些必须维护您的代码的人更清楚地看到它,并帮助您防止意外输入错误的数字。

    在我上面的示例中,我假设您的阵列包含从太阳到行星的距离。太阳将是第零个元素,因此 arrayOfNumbers[kDistanceToSun] = 0。然后随着您的增加,每个元素都包含到下一个最远行星的距离:水星、金星等。这比仅仅输入数字更具可读性你想要的星球。在这种情况下,数组的大小是固定的,因为有固定数量的行星(嗯,除了整个冥王星崩溃)。

    另一个问题是“arrayOfNumbers”没有告诉我们数组的内容。我们已经知道它是一个数字数组,因为我们在您说int arrayOfNumers[12345]; 的地方看到了声明,或者您声明了它。取而代之的是:

    int distanceToPlanetsFromSol[kNumberOfPlanets];
    

    ...让我们更好地了解数据实际上是什么以及它的语义是什么。作为程序员,您的目标之一应该是以这种方式编写自记录的代码。

    然后我们可以在其他地方争论 kNumberOfPlanets 应该是 8 还是 9。:)

    【讨论】:

    • 这取决于你是否数过火星。
    【解决方案3】:

    您应该问自己为什么要访问该特定职位。在这种情况下,我假设如果你在做arrayOfNumbers[6],第六个位置有一些特殊的含义。如果您认为这是什么意思,您可能会意识到这是一个隐藏它的神奇数字。

    【讨论】:

      【解决方案4】:

      另一种看待它的方式:

      如果程序需要访问第 7 个元素而不是第 6 个元素怎么办?您或维护者如何知道这一点?例如,如果第 6 个条目是 CA 中的树数,那么放入将是一件好事

       #define CA_STATE_ENTRY 6
      

      然后,如果现在对表重新排序,那么有人可以看到他们需要将其更改为 9(比如说)。顺便说一句,我并不是说这是按状态维护树计数数组的最佳方法 - 它可能不是。

      同样,如果后来人们想改变程序来处理俄勒冈州的树木,那么他们就知道要替换

       trees[CA_STATE_ENTRY]
      

       trees[OR_STATE_ENTRY]
      

      重点是

       trees[6]
      

      不是自我记录

      当然对于 c++ 它应该是一个枚举而不是一个#define

      【讨论】:

        【解决方案5】:

        您必须提供更多上下文才能获得有意义的答案。并不是所有的字面数字都是神奇的,但很多都是。在这种情况下,根本无法确定,尽管大多数情况下我可以想到带有显式数组索引 >>1 的副手可能符合魔术。

        【讨论】:

          【解决方案6】:

          并非程序中的所有字面量都真正符合“幻数”的条件——但这似乎确实如此。 6 不告诉我们您为什么要访问数组的特定元素。

          不是是一个神奇的数字,即使在第一次检查(或至少最小检查)时,您也需要非常清楚它的含义,为什么要使用该值。举个例子,很多代码会做这样的事情:&x[0]。在这种情况下,“0”实际上只是表示“数组的开头”,通常很清楚。

          【讨论】:

            【解决方案7】:

            如果您需要访问数组的特定元素,您可能做错了。

            您应该几乎总是遍历整个数组。

            【讨论】:

              【解决方案8】:

              如果您的程序正在做一些特别涉及数字 6 的非常特殊的事情,那么它就不是一个神奇的数字。你能提供一些上下文吗?

              【讨论】:

                【解决方案9】:

                这就是教授的问题,他们往往过于学术。理论上他是对的,像往常一样,但通常幻数在更严格的上下文中使用,当数字嵌入到 data 流中时,允许您检测流的某些属性(如签名标头例如文件类型)。 另见this Wikipedia entry

                【讨论】:

                • 该死的,你写的正是我要写的。 +1。
                【解决方案10】:

                通常,并非软件中的所有常量值都称为幻数。 java 类文件总是以十六进制值 0xcafebabe 开头一个 windows .exe 带有 MZ 0x4d, 0x5a 的文件,这可以让您快速(但不确定)识别 二进制文件的内容。

                【讨论】:

                  【解决方案11】:

                  在符合 MISRA 的系统中,除 0 和 1 之外的所有值都被视为幻数。我的观点一直是,如果常数值很明显或可能不会改变,那么将其保留为数字。如果有疑问,请创建一个唯一常量,因为长期维护会更容易。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2017-01-18
                    • 2014-06-11
                    • 2011-06-23
                    • 2013-10-24
                    • 2013-07-04
                    • 2022-01-05
                    • 1970-01-01
                    • 2013-01-02
                    相关资源
                    最近更新 更多