亲宝软件园·资讯

展开

LLVM Coding Standards - 中文翻译

小胖西瓜 人气:1
# LLVM 编码规范 **LLVM Coding Standards [官网](https://llvm.orghttps://img.qb5200.com/download-x/docs/CodingStandards.html) | 历史翻译版本 [Github](https://github.com/zxhio/coding)** - [导论](#intro) - [语言、库和标准](#lang) - [C++ 标准版本](#cppver) - [C++ 标准库](#stdlib) - [Go 代码准则](#go_guid) - [机械的代码问题](#src_issues) - [代码格式化](#src_fmt) - [注释](#comment) - [头文件](#comment_header) - [类概述](#class_overview) - [method information](#method_info) - [注释格式化](#comment_fmt) - [使用Doxygen注释](#comment_doxygen) - [错误和警告消息](#err_warn_msg) - [#include 风格](#include_style) - [代码宽度](#src_width) - [空格](#whitespace) - [格式化lambda如同代码块](#lambda_fmt) - [花括号初始化列表](#init_list_fmt) - [语言和编译器问题](#lang_compile_issue) - [像错误一样对待编译警告](#compile_warn) - [编写可移植的代码](#portable_code) - [不要使用 RTTI 或 Exceptions](#no_rtti_exception) - [不要使用静态构造函数](#no_static_ctor) - [使用class和struct关键字](#class_struct) - [不要使用花括号初始化列表调用构造函数](#no_brace_call_ctor) - [使用auto类型推导提高代码可读性](#auto) - [小心auto带来不必要的拷贝](#beware_auto_copy) - [小心对指针排序带来的不确定性](#beware_order_pointer) - [小心相同元素不确定的排序顺序](#beware_equal_order) - [风格问题](#fmt_issue) - [上层问题](#high_level_issue) - [头文件独立](#header_self_include) - [库层次](#lib_layering) - [尽可能减少 #include](#little_include) - [保持私有的内部头文件](#intenal_header) - [使用 namespace 限定符来实现之前声明的函数](#namespace_impl) - [提前退出或 continue 以简化代码](#early_exit_continue) - [return 之后不要使用 else](#no_else_after_return) - [将判断循环转换为判断函数](#predicate_loop_func) - [底层问题](#low_level_issue) - [合适的类型、函数、变量和枚举命名](#name) - [善用断言](#assert) - [不要使用 using namesapce std](#no_namespace_std) - [为头文件中的类提供虚函数锚](#virtual_method) - [不要在全覆盖枚举的switch 中使用 default](#no_default_in_switch) - [尽可能的使用基于范围的循环](#range_based_loop) - [不要每次通过循环取 end()](#eval_end) - [禁止包含 iostream](#forbidden_iostream) - [使用 raw_stream](#raw_stream) - [避免 std::endl](avoid_std_endl) - [不要在class中声明的函数中使用 inline](#no_class_inline) - [微观细节](#micro_details) - [括号之前的空格](#space_before_parentheses) - [推荐前置自增](#preincrement) - [namespace 缩进](#namespace_indent) - [匿名 namespace](#anonymous_namespace) - [其它参考](#see_also) ## 导论 This document describes coding standards that are used in the LLVM project. Although no coding standards should be regarded as absolute requirements to be followed in all instances, coding standards are particularly important for large-scale code bases that follow a library-based design (like LLVM). While this document may provide guidance for some mechanical formatting issues, whitespace, or other “microscopic details”, these are not fixed standards. Always follow the golden rule: **If you are extending, enhancing, or bug fixing already implemented code, use the style that is already being used so that the source is uniform and easy to follow.** Note that some code bases (e.g. libc++) have special reasons to deviate from the coding standards. For example, in the case of libc++, this is because the naming and other conventions are dictated by the C++ standard. There are some conventions that are not uniformly followed in the code base (e.g. the naming convention). This is because they are relatively new, and a lot of code was written before they were put in place. Our long term goal is for the entire codebase to follow the convention, but we explicitly do not want patches that do large-scale reformatting of existing code. On the other hand, it is reasonable to rename the methods of a class if you’re about to change it in some other way. Please commit such changes separately to make code review easier. The ultimate goal of these guidelines is to increase the readability and maintainability of our common source base. 本文档介绍在 *LLVM* 工程中使用的编码规范。尽管在任何情况下编码规范不应该被视为绝对遵循的需求,但是编码规范对于遵循基于库的设计(例如 LLVM)的大规模代码库而言尤为重要。 本文可能给一些机械的格式问题,空格或者其它细微的细节提供指引,不过没有固定的规范。始终遵守黄金规则: **使用当前的代码规范对已经实现的代码进行扩展,增强或者bug修复,这样源码风格统一并且易于遵守。** 注意,某些代码库(如libc++)有特殊的理由偏离此代码规范。比方说libc++,其命名和其它约定是由C++标准决定的。 在代码库中有一些约定没有被统一遵循(如命名约定)。这是因为这些约定相对较新而非常多的代码在这些约定出现之前就已经存在了。我们长期目标是整个代码库都遵循约定,但是我们明确不希望出现对现有代码进行大规模重新格式化的补丁。另一方面,如果你要以其它方式进行修改,则重命名类的方法是合理的。请分别提交此类修改,以便更容易地进行代码审查。 这些准则的最终目标就是提高我们公共源码库的可读性和可维护性。 ## 语言、库和标准 Most source code in LLVM and other LLVM projects using these coding standards is C++ code. There are some places where C code is used either due to environment restrictions, historical restrictions, or due to third-party source code imported into the tree. Generally, our preference is for standards conforming, modern, and portable C++ code as the implementation language of choice. 大部分在 *LLVM* 和其它 *LLVM* 项目中使用该代码规范的源码为C++代码。由于一些环境、历史限制或者引入至源码树中的第三方源码导致在某些地方存在C代码。通常而言,我们倾向于符合标准,现代和可移植的C++代码作为选择实现的语言。 ## C++ 标准版本 Unless otherwise documented, LLVM subprojects are written using standard C++14 code and avoid unnecessary vendor-specific extensions. Nevertheless, we restrict ourselves to features which are available in the major toolchains supported as host compilers (see Getting Started with the LLVM System page, section Software). Each toolchain provides a good reference for what it accepts: - Clang: https://clang.llvm.org/cxx_status.html - GCC: https://gcc.gnu.org/projects/cxx-status.html#cxx14 - MSVC: https://msdn.microsoft.com/en-us/library/hh567368.aspx 除非另有说明,否则 *LLVM* 子项目使用 *C++14* 标准编写并且避免不必要的厂商定制扩展。然而,我们将自己限制在宿主编译器支持的主要工具链中的可用功能之中(见[LLVM系统入门](https://llvm.orghttps://img.qb5200.com/download-x/docs/GettingStarted.html), 软件部分)。 每一个工具链都提供了一个好的参考: - Clang: https://clang.llvm.org/cxx_status.html - GCC: https://gcc.gnu.org/projects/cxx-status.html#cxx14 - MSVC: https://msdn.microsoft.com/en-us/library/hh567368.aspx ## C++ 标准库 Instead of implementing custom data structures, we encourage the use of C++ standard library facilities or LLVM support libraries whenever they are available for a particular task. LLVM and related projects emphasize and rely on the standard library facilities and the LLVM support libraries as much as possible. LLVM support libraries (for example, ADT) implement specialized data structures or functionality missing in the standard library. Such libraries are usually implemented in the llvm namespace and follow the expected standard interface, when there is one. When both C++ and the LLVM support libraries provide similar functionality, and there isn’t a specific reason to favor the C++ implementation, it is generally preferable to use the LLVM library. For example, llvm::DenseMap should almost always be used instead of std::map or std::unordered_map, and llvm::SmallVector should usually be used instead of std::vector. We explicitly avoid some standard facilities, like the I/O streams, and instead use LLVM’s streams library (raw_ostream). More detailed information on these subjects is available in the LLVM Programmer’s Manual. For more information about LLVM’s data structures and the tradeoffs they make, please consult [that section of the programmer’s manual](https://llvm.orghttps://img.qb5200.com/download-x/docs/ProgrammersManual.html#picking-the-right-data-structure-for-a-task). 只要能用于特定的任务,我们推荐使用C++标准库或者LLVM支持的库设施,而不是自定义用户数据结构。LLVM和相关项目尽可能的突出和依赖标准库和LLVM支持的库设施。 LLVM支持的库(例如ADT)实现了标准库缺少的特有数据结构或者功能。一些库经常被实现在`llvm`命名空间内并且遵循预期的标准接口。 当C++标准库和LLVM支持的库都支持一个相似的功能时,并且没有特定的理由去偏向C++标准库的实现,这种情况通常更倾向于使用LLVM的库。举个例子:`llvm::DenseMap` 几乎总是应该被使用而不是 `std::map` 或者 `std::unordered_map`,并且 `llvm::SmallVector` 应该总是代替使用 `std::vector`。我们明确的避免使用一些标准库设施,如标准 I/O stream,取而代之的是使用 LLVM 的 stream库([raw_ostream](https://llvm.orghttps://img.qb5200.com/download-x/docs/CodingStandards.html#raw-ostream))。更多相关主题的细节信息参考 [LLVM 开发者手册](https://llvm.orghttps://img.qb5200.com/download-x/docs/ProgrammersManual.html). 更多关于LLVM数据结构和做出权衡的信息,请参考 [that section of the programmer’s manual](https://llvm.orghttps://img.qb5200.com/download-x/docs/ProgrammersManual.html#picking-the-right-data-structure-for-a-task)。 ## Go 代码准则 Any code written in the Go programming language is not subject to the formatting rules below. Instead, we adopt the formatting rules enforced by the gofmt tool. Go code should strive to be idiomatic. Two good sets of guidelines for what this means are Effective Go and Go Code Review Comments. 任何使用Go语言的写下的代码不受以下(指C++)的格式化规则约束,相反的,我们使用[gofmt](https://golang.org/cmd/gofmt/)工具强制执行格式化规则。 Go 代码应该尽量符合习惯。[Effective Go](https://golang.orghttps://img.qb5200.com/download-x/doc/effective_go.html) 和 [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) 是两套好的准则。 ## 机械的代码问题 ### 代码格式化 #### 注释 Comments are important for readability and maintainability. When writing comments, write them as English prose, using proper capitalization, punctuation, etc. Aim to describe what the code is trying to do and why, not how it does it at a micro level. Here are a few important things to document: 注释对于可读性和可维护性非常重要。当写注释时,使用适当的大小写、标点符号等将其写成英文句子。专注于描述代码试图做什么和为什么这么做,不要从微观的角度去描述代码做的事情。以下是一些重要的记录: #### 头文件 Every source file should have a header on it that describes the basic purpose of the file. The standard header looks like this: A few things to note about this particular format: The “-*- C++ -*-” string on the first line is there to tell Emacs that the source file is a C++ file, not a C file (Emacs assumes .h files are C files by default). > This tag is not necessary in .cpp files. The name of the file is also on the first line, along with a very short description of the purpose of the file. The next section in the file is a concise note that defines the license that the file is released under. This makes it perfectly clear what terms the source code can be distributed under and should not be modified in any way. The main body is a Doxygen comment (identified by the /// comment marker instead of the usual //) describing the purpose of the file. The first sentence (or a passage beginning with \brief) is used as an abstract. Any additional information should be separated by a blank line. If an algorithm is based on a paper or is described in another source, provide a reference. 每一个源码文件应该有一个描述该文件基本用途的头部首部,标准的首部看起来像这样: ```cpp //===-- llvm/Instruction.h - Instruction class definition -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file contains the declaration of the Instruction class, which is the /// base class for all of the VM instructions. /// //===----------------------------------------------------------------------===// ``` 注意其中的一些特殊的格式:`-*- C++ -*-` 用于指示Emacs该文件为C++文件而不是C文件,(在Emacs中头文件默认为C文件)。 > 注意该标记在 .cpp 文件中不是必要的。文件名及一句简短的文件用途描述存在在文件的第一行。 文件的下一部分是一个简短的说明,它定义了文件发布所依据的 *license*。这样就清楚的说明了源代码在什么条件下可以发布,并且不能以任何形式进行修改。 主体部分是一些描述该文件用途的*Doxygen*注释(通过 `///` 注释记号而不是 `//`来标记)。第一句(段落以 `\brief`开始)用作于摘要。任何附加的信息都应该以空行分隔。如果一个算法是基于一篇论文或者在其它来源说明的,则提供一个引用。 #### 类概述 Classes are a fundamental part of an object-oriented design. As such, a class definition should have a comment block that explains what the class is used for and how it works. Every non-trivial class is expected to have a doxygen comment block. 类是面向对象设计的基础部分。一个类定义应该有一个描述该类的用途和如何工作的注释块。每一个非平凡类都应该有一个*doxygen*注释块。 #### 方法信息 Methods and global functions should also be documented. A quick note about what it does and a description of the edge cases is all that is necessary here. The reader should be able to understand how to use interfaces without reading the code itself. Good things to talk about here are what happens when something unexpected happens, for instance, does the method return null? 方法和全局函数同样应该被记录。简单备注一下它的功能和对边缘情况的描述。读者应该能够理解如何在不阅读代码本书的情况下使用接口。 这里更值得讨论的事情是当意外出现时会发生什么,例如,方法是否返回null? ### 注释格式化 In general, prefer C++-style comments (// for normal comments, /// for doxygen documentation comments). There are a few cases when it is useful to use C-style (/* */) comments however: 1. When writing C code to be compatible with C89. 2. When writing a header file that may be #included by a C source file. 3. When writing a source file that is used by a tool that only accepts C-style comments. 4. When documenting the significance of constants used as actual parameters in a call. This is most helpful for bool parameters, or passing 0 or nullptr. The comment should contain the parameter name, which ought to be meaningful. For example, it’s not clear what the parameter means in this call: ```cpp Object.emitName(nullptr); ``` An in-line C-style comment makes the intent obvious: ```cpp Object.emitName(/*Prefix=*/nullptr); ``` Commenting out large blocks of code is discouraged, but if you really have to do this (for documentation purposes or as a suggestion for debug printing), use #if 0 and #endif. These nest properly and are better behaved in general than C style comments. 通常而言,更倾向于C++风格的注释(`//` 为一般的注释,`///` 为*doxygen*文档注释)。不过有一小部分情况下C风格注释也是有用的: 1. 兼容C89的C代码 2. 只被C源文件包含的头文件 3. C源文件内只接受C风格的注释 4. 记录调用中实参常量的重要性。这对用于bool类型、0或nullptr有极大帮助。注释应该包含有意义的参数名字。举个例子,有一个参数含义不清晰的调用: ```cpp Object.emitName(nullptr); ``` 一行C风格注释使其意图变得明显: ```cpp Object.emitName(/*Prefix=*/nullptr); ``` 不推荐对大规模代码块进行注释,如果必须要注释的话(记录意图或者作为调试打印的建议),使用 `#if 0` 和 `#endif`。 适当的嵌套是比一般的使用C风格注释更好的行为。 ### 使用doxygen注释 Use the \file command to turn the standard file header into a file-level comment. Include descriptive paragraphs for all public interfaces (public classes, member and non-member functions). Avoid restating the information that can be inferred from the API name. The first sentence (or a paragraph beginning with \brief) is used as an abstract. Try to use a single sentence as the \brief adds visual clutter. Put detailed discussion into separate paragraphs. To refer to parameter names inside a paragraph, use the \p name command. Don’t use the \arg name command since it starts a new paragraph that contains documentation for the parameter. Wrap non-inline code examples in \code ... \endcode. To document a function parameter, start a new paragraph with the \param name command. If the parameter is used as an out or an in/out parameter, use the \param [out] name or \param [in,out] name command, respectively. To describe function return value, start a new paragraph with the \returns command. A minimal documentation comment: A documentation comment that uses all Doxygen features in a preferred way: 使用 `\file` 指令将标准文件首部转为文件级别的注释。 包括所有的公共接口(公共类、成员和非成员函数)描述性段落。避免重复可以从 API 名字中获取的信息。第一句(对段落而言以 `\brief` 开始)用作于一个概述。用单个句子作为 `\brief` 的补充,具体的细节讨论放在下一段落之中。 使用 `\p name` 指令在段落注释中引用参数的名称。不要在包含参数描述的新段落中使用 `\arg name` 指令。 使用 `\code ... \endcode` 指令来包装非内联代码。 新起一个段落使用 `\param name` 指令来描述一个函数的参数,如果是用来输出或者输入输出的参数,使用 `\param [out] name` 或者 `\param [in,out] name` 指令来表示。 新起一段使用 `\returns` 来描述函数的返回。 一个最简短的文档注释 。。。 ```cpp /// Sets the xyzzy property to \p Baz. void setXyzzy(bool Baz); ``` 一个首选的文档注释是使用所有的 *doxygen* 特性。 ```cpp /// Does foo and bar. /// /// Does not do foo the usual way if \p Baz is true. /// /// Typical usage: /// \code /// fooBar(false, "quux", Res); /// \endcode /// /// \param Quux kind of foo to do. /// \param [out] Result filled with bar sequence on foo success. /// /// \returns true on success. bool fooBar(bool Baz, StringRef Quux, std::vector

加载全部内容

相关教程
猜你喜欢
用户评论