NEP 45 — C 风格指南#
- 作者:
Charles Harris <charlesr.harris@gmail.com>
- 状态:
活跃
- 类型:
流程
- 创建时间:
2012-02-26
- 解决时间:
摘要#
本文档提供了构成 NumPy C 实现的 C 代码的编码约定。
动机与范围#
NumPy C 编码约定基于 Guido van Rossum 的 Python PEP 7 – C 代码风格指南,并增加了一些限制。
由于 NumPy 约定与 PEP 7 中的约定非常接近,因此 PEP 7 被用作模板,并在适当的位置加入了 NumPy 的补充和变动。
用法与影响#
C 编码约定有很多,必须强调的是,NumPy 约定的主要目标不是选择“最好”的,因为对此肯定会有分歧,而是实现统一。
打破特定规则的两个好理由
当应用规则会使代码可读性降低时,即使对于习惯阅读遵循规则的代码的人来说也是如此。
为了与周围同样打破规则的代码保持一致(可能出于历史原因)——尽管这也可以是一个清理他人烂摊子的机会。
向后兼容性#
无影响。
详细描述#
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++ 成功,这个形式可能会被放宽,以便短的类方法(打算内联)可以将返回类型放在函数名的同一行。然而,这还有待确定。
代码结构:关键字(如
if、for)与后面的左括号之间有一个空格;括号内部没有空格;所有if分支都用花括号括起来,并且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!
如果函数和全局变量在当前编译单元之外不需要,则应将其声明为 static。
在头文件中声明外部函数和变量。
命名约定#
NumPy 公共函数还没有统一的前缀,但它们都以某种形式的前缀开头,后跟一个下划线,并且使用驼峰命名法:
PyArray_DescrAlignConverter、NpyIter_GetIterNext。将来,名称应采用Npy*_PublicFunction的形式,其中星号是适当的内容。公共宏应具有
NPY_前缀,然后使用大写字母,例如NPY_DOUBLE。私有函数应使用小写字母和下划线,例如:
array_real_get。不应使用单个前导下划线,但由于历史原因,一些当前函数名违反了此规则。
注意
名称以单个下划线开头的函数应在某个时候重命名。
函数文档#
NumPy 目前没有 C 函数文档标准,但需要一个。大多数 NumPy 函数不在代码中进行文档化,这种情况应该改变。一种可能性是使用 Doxygen 插件,以便 NumPy 用于 Python 函数的相同样式也可以用于文档化 C 函数,请参阅 doc/cdoc/ 中的文件。
讨论#
numpy/numpy#11911 建议将此提案(最初为 doc/C_STYLE_GUIDE.rst)转换为 NEP。
版权#
本文档已置于公共领域。