代码之家  ›  专栏  ›  技术社区  ›  Bryan Rowe

不断滥用?

  •  19
  • Bryan Rowe  · 技术社区  · 16 年前

    我在一些具有以下常量的C项目中遇到了一组代码:

        const int ZERO_RECORDS = 0;
        const int FIRST_ROW = 0;
        const int DEFAULT_INDEX = 0;
        const int STRINGS_ARE_EQUAL = 0;
    

    有人见过这样的东西吗?是否有任何方法可以合理化使用常量来表示语言结构?即:C数组中的第一个索引位于位置0。我认为,如果开发人员需要依赖一个常量来告诉他们语言是基于0的,那么就存在一个更大的问题。

    这些常量最常见的用法是在处理数据表或“for”循环中。

    我是不是觉得这是一种代码味道?我觉得这并不比:

    const int ZERO = 0;
    const string A = "A";
    
    17 回复  |  直到 14 年前
        1
  •  10
  •   gbn    16 年前

    滥用,imo。“零”只是一个基本要素。

    尽管字符串“等于”可能很容易,为什么不“等于”呢?

    Accepted limited use of magic numbers?

        2
  •  12
  •   Anon.    16 年前

    我是不是觉得这是一种代码味道?我觉得这并不比:

    比较以下各项:

    if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL) ...
    

    具有

    if(str1.CompareTo(str2) == ZERO) ...
    if(str1.CompareTo(str2) == 0) ...
    

    哪个更直接?

        3
  •  5
  •   Tom Neyland    16 年前

    那绝对是一种代码味道。

    其目的可能是“增加代码的可读性”,但在我看来,这实际上降低了代码的可读性。

        4
  •  5
  •   tloach    16 年前

    有些人认为程序中的任何原始数字都是“幻数”。我见过一些编码标准,它们基本上说你不能只把一个整数写进一个程序,它必须是一个常量。

        5
  •  3
  •   micahtan    16 年前

    我是不是觉得这是一种代码味道?我觉得这并不比:

    常量int zero=0;

    常量a='a';

    可能有点味道,但肯定比0=0和a='a好。在第一种情况下,它们定义逻辑常量,即一些抽象概念(字符串相等)和具体的值实现。

    在您的示例中,您定义的是文字常量——变量本身表示值。如果是这种情况,我会认为枚举是首选的,因为它们很少是奇异值。

        6
  •  3
  •   Earlz    16 年前

    这确实是个糟糕的编码。

    我说常量应该只在需要的地方使用,在以后可能发生变化的地方。例如,我有很多“配置”选项,比如 SESSION_TIMEOUT 定义了它应该保持不变的地方,但也许可以在以后的道路上进行调整。我不认为 ZERO 可以在路上调整。

    此外,对于幻数,不应包括零。

    我有点奇怪,但我觉得这个信念很奇怪,因为我会说这样的话会有很大的发展。

    //input is FIELD_xxx where xxx is a number
    input.SubString(LENGTH_OF_FIELD_NAME); //cut out the FIELD_ to give us the number
    
        7
  •  2
  •   Adriaan Stander    16 年前
        8
  •  2
  •   stefanB    16 年前

    我认为有时人们盲目地遵循“编码标准” 这意味着“不要使用硬编码的值,将它们定义为常量,以便在需要更新代码时更容易管理代码”——这对于以下内容是足够公平的:

    const in MAX_NUMBER_OF_ELEMENTS_I_WILL_ALLOW = 100
    

    但对以下情况没有意义:

    if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL)
    

    因为 每次我看到这个代码,我都需要搜索 STRINGS_ARE_EQUAL 定义为 然后检查文档是否正确。

    相反,如果我看到:

    if(str1.CompareTo(str2) == 0)
    

    我跳过步骤1(搜索 STRINGS_ARE... 定义为),可以检查规格值 0 手段。

    你想把这个换成 Equals() 使用 CompareTo() 如果您感兴趣的案例不止一个,例如:

    switch (bla.CompareTo(bla1))
    {
         case IS_EQUAL:
         case IS_SMALLER:
         case IS_BIGGER:
         default:
    }
    

    使用 if/else 声明(不知道是什么) 并列() 返回…

    我仍然会检查您是否根据规范正确定义了这些值。

    如果规范定义了 ComparisonClass::StringsAreEqual 值或类似的东西(我刚刚编了一个),那么您将不会使用0,而是使用适当的变量。

    所以,这取决于您何时特别需要访问数组中的第一个元素 arr[0] 比…好 arr[FIRST_ELEMENT] 因为我还是会去检查你定义的 FIRST_ELEMENT 因为我不相信你,这可能与 -例如,您的 0 元素是dud,实际的第一个元素存储在 1 -谁知道呢。

        9
  •  1
  •   Tim Robinson    16 年前

    我要找代码气味。如果需要这些类型的常量,请将它们放入枚举中:

    enum StringEquality
    {
        Equal,
        NotEqual
    }
    

    (不过我怀疑 STRINGS_ARE_EQUAL 是什么被退回 string.Compare ,因此,对其进行黑客攻击以返回枚举可能会更详细。)

    编辑: 阿尔索 SHOUTING_CASE 不是特别的 .NET-style naming convention .

        10
  •  1
  •   Paul Sasik    16 年前

    我不知道我是否会称它们为气味,但它们似乎是多余的。尽管默认索引实际上是有用的。

    重点是 避免使用幻数 零并不是真正的魔法。

        11
  •  1
  •   Daniel    16 年前

    这是你办公室里的代码还是你下载的代码?

    如果是在办公室里,我认为如果人们随意地在周围放置常量,这是管理层的问题。在全球范围内,不应该有任何常数,除非每个人都对这些常数的用途有明确的概念或共识。

    在C中,理想情况下,您希望创建一个类,该类保存所有其他类全局使用的常量。例如,

    class MathConstants
    {
     public const int ZERO=0;
    }
    

    然后在后面的课程中,比如:

    ....
    if(something==MathConstants.ZERO)
    ...
    

    至少我是这么看的。这样,每个人都可以理解这些常量是什么,而不必阅读任何其他内容。这样可以减少混乱。

        12
  •  1
  •   devuxer    16 年前

    一般来说,使用常数有四个原因:

    1. 作为未来可能发生合理变化的价值的替代品(例如, IdColumnNumber = 1 )。
    2. 作为一个本身不容易理解或有意义的值的标签(例如 FirstAsciiLetter = 65 )
    3. 作为一种较短且不易出错的键入较长或难以键入的值的方法(例如, LongSongTitle = "Supercalifragilisticexpialidocious" )
    4. 作为一个难以记忆的值的记忆辅助(例如, PI = 3.14159265 )

    对于您的特定示例,下面是我如何判断每个示例:

    const int ZERO_RECORDS = 0;
    // almost definitely a code smell
    
    const int FIRST_ROW = 0;
    // first row could be 1 or 0, so this potentially fits reason #2,
    // however, doesn't make much sense for standard .NET collections
    // because they are always zero-based
    
    const int DEFAULT_INDEX = 0;
    // this fits reason #2, possibly #1
    
    const int STRINGS_ARE_EQUAL = 0;
    // this very nicely fits reason #2, possibly #4
    // (at least for anyone not intimately familiar with string.CompareTo())
    

    所以,我想说,不,这些并不比 Zero = 0 A = "A" .

        13
  •  0
  •   Brian    16 年前

    如果零表示除零以外的其他值(在本例中,字符串_等于),那么这是不可思议的。为它创建一个常量是可以接受的,并且使代码更可读。

    创建一个称为零的常量是毫无意义的,而且浪费了手指的能量!

        14
  •  0
  •   Kena    16 年前

    闻起来有点异味,但我可以看到这样的情况,特别是如果你的程序员一直在从一种语言切换到另一种语言。

    例如,Matlab是一个索引,所以我可以想象有人厌倦了每当一个错误切换到语言,并在C++和MATLAB程序中定义Debug Type索引来抽象差异。不一定很优雅,但如果这就是需要的…

        15
  •  0
  •   grenade    16 年前

    好吧,你要质疑这个气味年轻的代码战士。然而,这些命名常量是从比Visual Studio早得多的编码实践中派生出来的。它们可能是多余的,但你可能做得比理解公约的起源还要糟糕。想想美国航空航天局的电脑,很久以前…

        16
  •  0
  •   Ken Lange    16 年前

    在跨平台的情况下,您可能会看到类似的情况,在这种情况下,您将使用具有适合平台的常量集的文件。但可能并没有这些实际的例子。这看起来像是一个COBOL编码人员试图让他的C看起来更像英语(对COBOL编码人员来说没有冒犯的意思)。

        17
  •  0
  •   David Braverman    16 年前

    使用常量来表示抽象值是可以的,但用您自己的语言表示构造则是另一回事。

    const int FIRST_ROW = 0 没有道理。

    const int MINIMUM_WIDGET_COUNT = 0 更有意义。

    您应该遵循编码标准的假设是有意义的。(也就是说,编码标准在一个组织内是假定正确的。)当假定不满足时,盲目地遵循它是没有意义的。

    因此,我同意早期的海报,一些气味常数可能是由于遵循编码标准(“无魔力数字”)到字母无例外。这就是问题所在。