PEP 7 – C 代码风格指南
- 作者:
- Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>
- 状态:
- 活跃
- 类型:
- 流程
- 创建日期:
- 2001年7月5日
- 发布历史:
引言
本文档提供了构成 Python C 实现的 C 代码的编码约定。请参阅描述 Python 代码风格指南的配套信息性 PEP。
请注意,规则就是用来打破的。打破特定规则的两个充分理由是:
- 当应用规则会使代码可读性变差时,即使对于习惯阅读遵循规则的代码的人来说也是如此。
- 为了与周围同样违反规则的代码保持一致(可能是历史原因)——尽管这也是一个清理他人烂摊子的机会(以真正的 XP 风格)。
C 标准
遵循以下标准。对于相关标准中不存在的特性,请使用 CPython 特定的包装器(例如:_Py_atomic_store_int32、Py_ALWAYS_INLINE、Py_ARITHMETIC_RIGHT_SHIFT;公共头文件中的 _Py_ALIGNED_DEF)。添加此类包装器时,请尝试使其易于针对不支持的编译器进行调整。
- Python 3.11 及更新版本使用 C11,不包含可选功能。公共 C API 应与 C99 和 C++ 兼容。
(提醒任何阅读此文的用户:此 PEP 是一个 风格指南;这些规则就是用来打破的。)
- Python 3.6 到 3.10 使用 C89,并选择了一些 C99 功能:
<stdint.h>和<inttypes.h>中的标准整数类型。我们要求固定宽度的整数类型。static inline函数- 指定初始化器(特别适用于类型声明)
- 混合声明
- 布尔值
- C++ 风格的行注释
- Python 3.6 之前的版本使用 ANSI/ISO 标准 C(1989 年版标准)。这意味着,除其他许多事情外,所有声明都位于块的顶部。
常见 C 代码约定
- 不要使用特定于编译器的扩展,例如 GCC 或 MSVC 的扩展。例如,不要在没有尾随反斜杠的情况下编写多行字符串。
- 所有函数声明和定义都必须使用完整原型。也就是说,指定所有参数的类型,并使用
(void)声明没有参数的函数。 - 主要编译器(gcc、VC++、其他一些)没有编译器警告。
- 新代码中应优先使用
static inline函数而不是宏。
代码布局
- 使用 4 个空格缩进,完全不使用制表符。
- 任何一行都不应超过 79 个字符。如果这条规则和前一条规则加在一起仍然没有给你足够的编码空间,那么你的代码就太复杂了——考虑使用子例程。
- 任何一行都不应以空白字符结尾。如果你认为你需要重要的尾随空白字符,请三思——别人的编辑器可能会例行地删除它。
- 函数定义风格:函数名在第 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; }
- 代码结构:在
if、for等关键字和紧随其后的左括号之间留一个空格;括号内不留空格;所有地方都需要花括号,即使 C 允许省略它们,但不要将它们添加到你没有其他修改的代码中。所有新的 C 代码都需要花括号。花括号应按所示格式化:if (mro != NULL) { ... } else { ... }
- return 语句 不应 有多余的括号
return(albatross); /* incorrect */
而是:
return albatross; /* correct */
- 函数和宏调用风格:
foo(a, b, c)– 开括号前无空格,括号内无空格,逗号前无空格,每个逗号后一个空格。 - 赋值、布尔和比较运算符周围始终留有空格。在包含许多运算符的表达式中,在最外层(优先级最低)的运算符周围添加空格。
- 断开长行:如果可能,在最外层参数列表中的逗号后断开。始终适当缩进续行,例如:
PyErr_Format(PyExc_TypeError, "cannot create '%.100s' instances", type->tp_name);
- 当你在二元运算符处断开长表达式时,花括号应按所示格式化:
if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 && type->tp_dictoffset == b_size && (size_t)t_size == b_size + sizeof(PyObject *)) { return 0; /* "Forgive" adding a __dict__ only */ }
将运算符放在行尾是可以的,特别是为了与周围代码保持一致。(有关更长的讨论,请参阅 PEP 8。)
- 在多行宏中垂直对齐行继续符。
- 旨在用作语句的宏应使用
do { ... } while (0)宏惯用法,不带末尾分号。示例:#define ADD_INT_MACRO(MOD, INT) \ do { \ if (PyModule_AddIntConstant((MOD), (#INT), (INT)) < 0) { \ goto error; \ } \ } while (0) // To be used like a statement with a semicolon: ADD_INT_MACRO(m, SOME_CONSTANT);
- 使用后
#undef文件局部宏。 - 在函数、结构定义和函数内部的主要部分周围留空行。
- 注释放在它们描述的代码之前。
- 所有函数和全局变量都应声明为静态,除非它们是已发布接口的一部分。
- 对于外部函数和变量,我们总是在“Include”目录中的适当头文件中有一个声明,该声明使用
PyAPI_FUNC()宏和PyAPI_DATA()宏,如下所示:PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); PyAPI_DATA(PyTypeObject) PySuper_Type;
命名约定
- 公共函数使用
Py前缀;静态函数从不使用。Py_前缀保留用于全局服务例程,如Py_FatalError;特定的例程组(例如特定对象类型 API)使用更长的前缀,例如字符串函数的PyString_。 - 公共函数和变量使用混合大小写并带有下划线,例如:
PyObject_GetAttr、Py_BuildValue、PyExc_TypeError。 - 有时“内部”函数必须对加载器可见;我们为此使用
_Py前缀,例如:_PyObject_Dump。 - 宏应具有混合大小写前缀,然后使用大写,例如:
PyString_AS_STRING、Py_PRINT_RAW。 - 宏参数应使用
ALL_CAPS风格,以便它们易于与 C 变量和结构成员区分开来。
文档字符串
- 使用
PyDoc_STR()或PyDoc_STRVAR()宏用于文档字符串,以支持在没有文档字符串的情况下构建 Python(./configure --without-doc-strings)。 - 每个函数文档字符串的第一行应是“签名行”,简要概述参数和返回值。例如:
PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n\ Determine whether name and value make a valid pair.");
在签名行和描述文本之间始终包含一个空行。
如果函数的返回值始终是
None(因为没有有意义的返回值),则不要包含返回类型指示。 - 编写多行文档字符串时,请务必始终使用反斜杠延续,如上例所示,或字符串字面量连接:
PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n" "Determine whether name and value make a valid pair.");
尽管有些 C 编译器接受不带这两种方式的字符串字面量:
/* BAD -- don't do this! */ PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n Determine whether name and value make a valid pair.");
但并非所有都接受;已知 MSVC 编译器会对此发出警告。
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0007.rst