【问题标题】:Does the concept of "magic number" change from language to language?“幻数”的概念是否因语言而异?
【发布时间】:2011-07-16 05:25:39
【问题描述】:

以下面的C/C++代码为例:

int foo[] = {0, 0, 0, 0};

没有神奇的数字,对吧?
现在,Python 的“等价物”将是:

foo = [0, 0, 0, 0]

仍然没有神奇的数字。
然而,在 Python 中,同样的事情可以这样写:

foo = [0] * 4

现在我们确实有一个神奇的数字。还是我们?
我猜这和其他类似的东西出现在这些和其他语言上。

【问题讨论】:

  • 我不知道你在说什么。
  • 这里有什么问题?
  • 我认为这不应该被关闭,但我也不认为问题的质量。答案太不具体了。
  • 这是一个糟糕的问题,但在让对方有机会澄清他在说什么之前关闭它是没有意义的。
  • 问题是“‘幻数’的概念会随着语言的变化而变化吗?”。我认为不需要澄清。

标签: c++ python c magic-numbers concept


【解决方案1】:

这与(在 C 或 C++ 中)有何不同:

int foo[4] = {0};

?

在所有这些情况下,数组的大小都是一个幻数。

【讨论】:

  • 所以我们必须明确地从幻数的定义中排除数组大小,以免在使用文字时隐式使用一个,对吧?
  • @flyingsheep:如果初始化器有一些结构,那么大小不再是“魔法”,而是有意义的。但是这里没有可见的结构,大小显得随意。
  • 除了int foo[4] = {1}; //[1,0,0,0]foo = [1] * 4 //[1,1,1,1]
  • @Andrew:所以?关键是所有提到的语言都允许明确指定维度。
  • Python 示例没有显式设置维度,它显式地将变量初始化为指定数组 ([0]*4),维度是基于该数组的大小隐含的。在 C/C++ 示例中,显式声明了维度,并且分别显式声明了初始数组,并且不需要与指定的维度相同。
【解决方案2】:

按我的理解,幻数是域值(用于计算,映射元素中的索引)。他们的想法在任何语言中都是一致的。在您的示例中,这取决于这些数组的用途。

【讨论】:

    【解决方案3】:

    并非每个号码都是magic constant4 和四个 0 是幻数(在任何语言中)的原因是完全不清楚为什么这个数字是 4 而不是任何其他数字。

    例如,在使用众所周知的六面骰子进行的游戏中

    def roll_die():
        return random.randint(1,6)
    

    这段代码没有神奇的数字,因为很容易看出数字的来源。

    另一方面,很难猜测其他程序员知道哪些数字。例如,不是每个人都可能知道一副牌中有多少张牌,因此在此处使用命名常量更有意义。

    一个数字是否“神奇”完全取决于上下文,它与语言无关。如有疑问,请为您的常量命名以防万一。

    【讨论】:

    • 骰子有 4、6、8、10、12 或 20 面 - 对于“die”的某些值。
    • 所以我猜答案是“否”?
    【解决方案4】:

    您的所有问题都表明,“幻数”的概念和在您的程序中禁止使用“幻数”的规则是完全愚蠢的。对于不了解自己在做什么的人来说,针对幻数的规则是很差的近似值,对于在多个地方硬编码必须一致或相互依赖的值的更明智的规则。例如,这段代码是完全合理的,只要缓冲区长度不需要匹配程序或现实世界中的任何其他内容:

    char buf[100];
    snprintf(buf, sizeof buf, ...);
    

    但是这段代码非常糟糕:

    char buf[100];
    snprintf(buf, 100, ...);
    

    当然,在现实世界中,可能您希望缓冲区大小匹配的东西,例如打印某个特定大小的整数所需的最大位数。在这种情况下,您可能需要以下内容:

    char buf[3*sizeof(int)+3];
    snprintf(buf, sizeof buf, ...);
    

    如果您认为CHAR_BIT 是可变的,那么您可能希望用CHAR_BIT 的公式替换3。无论如何,表达式中出现的常量都不是“邪恶的幻数”。

    在您的示例中,如果数组的维度取决于其他变量,那么您的所有三个数组定义都是不好的做法。但如果维度 4 是你所做工作的基础,我认为它没有任何问题。

    当然,您所做的事情有时会在代码的生命周期内发生变化,但这就是文档的用途。如果不进行某种程度的修改,就不能期望代码能够处理将来可能发生的目的变更,并且只要您记录了它的原始目的和合同是什么,那么更改这些内容的人应该不难找到代码的部分需要改变。

    【讨论】:

    • @R:虽然第二个代码 sn-p 肯定比第一个代码差,但我个人认为两者都不合理。第一个 sn-p 仍然让任何阅读它的人质疑为什么缓冲区的长度为100 - 该信息不包含在代码中的任何地方。这可能并不重要,但读者并不知道 - 以一种或另一种方式告诉他们(使用命名常量,或者至少是注释......)没有记录其假设的代码浪费人们的时间,并可能在以后导致不必要的错误。
    • 当您要求将 一些 的 100 更改为 256 时,您如何知道要更改哪些?
    • 我想我在第三个例子中跟进了。无论大小基于什么,明确的常数公式都是最好的。
    【解决方案5】:

    请看下面的代码。这是一个c语言特性。

      int arr[] = { [0 ... 4]=3,[7]=7,[8 ... 12]=12,[15]=0};
    

    相同

    int arr[] = { 3, 3, 3, 3, 3, 0, 0, 7, 12, 12, 12, 12, 12, 0, 0, 0 };

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      相关资源
      最近更新 更多