NEP 45 — C 风格指南#

作者

查尔斯·哈里斯 <查尔斯哈里斯@gmail ​ com >

地位

积极的

类型

过程

创建

2012-02-26

解决

numpy/numpy#11911

抽象的

本文档给出了包含 NumPy C 实现的 C 代码的编码约定。

动机和范围#

NumPy C 编码约定基于 Guido van Rossum 编写的 Python PEP 7 – C 代码风格指南, 并添加了一些限制。

由于 NumPy 约定与 PEP 7 中的约定非常接近,因此该 PEP 被用作模板,并在适当的位置添加了 NumPy 和变化。

使用和影响#

C 编码约定有很多,必须强调的是,NumPy 约定的主要目标不是选择“最佳”(对此肯定存在分歧),而是实现统一。

违反特定规则的两个充分理由:

  1. 应用规则会降低代码的可读性,即使对于习惯阅读遵循规则的代码的人也是如此。

  2. 与周围的代码保持一致,这些代码也会破坏它(也许是出于历史原因)——尽管这也是清理别人混乱的机会。

向后兼容性#

没有影响。

详细说明

C方言#

  • 使用C99(即ISO/IEC 9899:1999定义的标准)。

  • 不要使用 GCC 扩展(例如,不要编写没有尾部反斜杠的多行字符串)。最好将长字符串分成单独的行,如下所示:

    "blah blah"
    "blah blah"
    

    这适用于 MSVC,否则 MSVC 在很长的字符串上会被阻塞。

  • 所有函数声明和定义必须使用完整原型(即指定所有参数的类型)。

  • 主要编译器(gcc、VC++ 等)没有编译器警告。

笔记

NumPy 仍然会产生需要解决的编译器警告。

代码布局#

  • 使用 4 个空格缩进并且完全不使用制表符。

  • 每行长度不得超过 80 个字符。如果这条规则和前面的规则一起没有给你足够的空间来编码,那么你的代码太复杂了——考虑使用子例程。

  • 任何行都不应该以空格结尾。如果您认为需要大量尾随空格,请再考虑一下;某人的编辑可能会例行删除它。

  • 函数定义风格:函数名在第 1 列,最外面的大括号在第 1 列,局部变量声明后有空行:

    static int
    extra_ivars(PyTypeObject *type, PyTypeObject *base)
    {
        int t_size = PyType_BASICSIZE(type);
        int b_size = PyType_BASICSIZE(base);
    
        assert(t_size >= b_size); /* type smaller than base! */
        ...
        return 1;
    }
    

    如果过渡到 C++,这种形式可能会放宽,以便内联的短类方法可以将返回类型与函数名称放在同一行。然而,这还有待确定。

  • 代码结构:关键字之间有一个空格iffor后面的左括号;括号内不能有空格;所有分支都用大括号括起来,并且与.if在同一行上没有任何语句 。if它们的格式应如下所示:

    if (mro != NULL) {
        one_line_statement;
    }
    else {
        ...
    }
    
    
    for (i = 0; i < n; i++) {
        one_line_statement;
    }
    
    
    while (isstuff) {
        dostuff;
    }
    
    
    do {
        stuff;
    } while (isstuff);
    
    
    switch (kind) {
        /* Boolean kind */
        case 'b':
            return 0;
        /* Unsigned int kind */
        case 'u':
            ...
        /* Anything else */
        default:
            return 3;
    }
    
  • return 语句不应多余的括号:

    return Py_None; /* correct */
    return(Py_None); /* incorrect */
    
  • 函数和宏调用风格:,左括号前无空格,括号内无空格,逗号前无空格,每个逗号后有一个空格。foo(a, b, c)

  • 始终在赋值运算符、布尔运算符和比较运算符两边添加空格。在使用大量运算符的表达式中,请在最外面(最低优先级)运算符周围添加空格。

  • 换行长行:如果可以的话,在最外面的参数列表中的逗号后换行。始终适当缩进连续行:

    PyErr_SetString(PyExc_TypeError,
            "Oh dear, you messed up.");
    

    这里适当地表示至少一个双缩进(8 个空格)。没有必要将所有内容都与函数调用的左括号对齐。

  • 当您在二元运算符处中断长表达式时,该运算符将移至上一行的末尾,例如:

    if (type > tp_dictoffset != 0 &&
            base > tp_dictoffset == 0 &&
            type > tp_dictoffset == b_size &&
            (size_t)t_size == b_size + sizeof(PyObject *)) {
        return 0;
    }
    

    请注意,多行布尔表达式中的术语是缩进的,以便使代码块的开头清晰可见。

  • 在函数、结构定义和函数内的主要部分周围放置空行。

  • 注释位于其描述的代码之前。多行注释应该像这样:

    /*
     * This would be a long
     * explanatory comment.
     */
    

    应谨慎使用尾随注释。代替

    if (yes) { // Success!
    

    if (yes) {
        // Success!
    
  • 当当前编译单元之外不需要所有函数和全局变量时,应将它们声明为静态。

  • 在头文件中声明外部函数和变量。

命名约定#

  • NumPy 公共函数没有一致的前缀,但它们都以某种前缀开头,后跟下划线,并且采用驼峰式大小写:PyArray_DescrAlignConverter, NpyIter_GetIterNext。将来的名称应该采用以下形式Npy*_PublicFunction,其中星号是适当的。

  • 公共宏应该有一个NPY_前缀,然后使用大写,例如NPY_DOUBLE.

  • 私有函数应该是小写并带有下划线,例如: array_real_get。不应使用单前导下划线,但由于历史事故,某些当前函数名称违反了该规则。

笔记

名称以下划线开头的函数应该在某个时候重命名。

函数文档#

NumPy 目前没有 C 函数文档标准,但需要一个。大多数 NumPy 函数都没有记录在代码中,这一点应该改变。一种可能性是带有插件的 Doxygen,这样用于 Python 函数的相同 NumPy 风格也可以用于记录 C 函数,请参阅doc/cdoc/.

讨论

numpy/numpy#11911 建议将该提案(最初为doc/C_STYLE_GUIDE.rst)转变为 NEP。