滚动轴承程序设计c语言,Clean Code Style - 基础篇

目录

0b23cfa764d5

前言

“Clean Code That Works”,来自于Ron Jeffries这句箴言指导我们写的代码要整洁有效,Kent Beck把它作为TDD(Test Driven Development)追求的目标,BoB大叔(Robert C. Martin)甚至写了一本书来阐述他的理解。

整洁的代码不一定能带来更好的性能,更优的架构,但它却更容易找到性能瓶颈,更容易理解业务需求,驱动出更好的架构。整洁的代码是写代码者对自己技艺的在意,是对读代码者的尊重。

本文是对BOB大叔《Clen Code》

致谢

本文由李永顺编写,并由丁辉、范璟玮、王博、金华、张超、曾亮亮、尉刚强等参与评审,并提出了非常好的修改意见,在此表示诚挚的感谢。

但由于时间的仓促及作者水平有限,如果您发现了本文的错误,或者有其他更好的意见,请第一时间告诉我们,我们将非常感激.

I 基础级

基础级主要包括代码格式、注释、物理设计三部分,这三部分比较容易做到,甚至可以制定为团队的编码规范,保证团队代码保持统一风格。

1.1 格式

遵循原则:

关系密切内容聚合

关系松散内容分隔

注意事项:

编码时使用等宽字体

替换Tab为4个空格

使用统一的编码格式:UTF-8, GB2312, GBK

使用统一的代码格式化风格。例如经典风格 K&R, BSD/Allman, GNU, Whitesmiths

控制行宽,不需要拖动水平滚动条查看代码

使用卫语句取代嵌套表达式

1.1.1 横向格式

使用空格对内容进行分隔,使用锯齿缩紧对代码段进分隔

反例:

public String toString() {

Point point=new Point();

StringBuilder sb=new StringBuilder();

sb.append("A B C D E F G H");

for(point.x=0;point.x

sb.append('\n').append(point.x + 1);

for(point.y=0;point.y

sb.append(' ').append(board.get(point).symbol());

}

}

sb.append('\n');

return sb.toString();

}

正例:

public String toString() {

Point point = new Point();

StringBuilder sb = new StringBuilder();

sb.append(" A B C D E F G H");

for (point.x = 0; point.x < BOARD_LENGTH; point.x++) {

sb.append('\n').append(point.x + 1);

for (point.y = 0; point.y < BOARD_WIDTH; point.y++) {

sb.append(' ').append(board.get(point).symbol());

}

}

sb.append('\n');

return sb.toString();

}

1.1.2 纵向格式

使用空行对内容进行分隔,函数或类的方法不要太长,尽量能在视野范围内一览无余

反例:

public class ComparisonCompactor {

private static final String ELLIPSIS = "...";

private static final String DELTA_END = "]";

private static final String DELTA_START = "[";

private int fContextLength;

private String fExpected;

private String fActual;

private int fPrefix;

private int fSuffix;

@SuppressWarnings("deprecation")

public String compact(String message) {

if (fExpected == null || fActual == null || areStringsEqual()) {

return Assert.format(message, fExpected, fActual);

}

findCommonPrefix();

findCommonSuffix();

String expected = compactString(fExpected);

String actual = compactString(fActual);

return Assert.format(message, expected, actual);

}

private boolean areStringsEqual() {

return fExpected.equals(fActual);

}

}

正例:

public class ComparisonCompactor {

private static final String ELLIPSIS = "...";

private static final String DELTA_END = "]";

private static final String DELTA_START = "[";

private int fContextLength;

private String fExpected;

private String fActual;

private int fPrefix;

private int fSuffix;

@SuppressWarnings("deprecation")

public String compact(String message) {

if (fExpected == null || fActual == null || areStringsEqual()) {

return Assert.format(message, fExpected, fActual);

}

findCommonPrefix();

findCommonSuffix();

String expected = compactString(fExpected);

String actual = compactString(fActual);

return Assert.format(message, expected, actual);

}

private boolean areStringsEqual() {

return fExpected.equals(fActual);

}

}

1.2 注释

遵循原则:

尽量不写注释,尝试用代码自阐述

必要时增加注释

注意事项:

擅用源码管理工具

提交代码时,日志要详细

避免使用中文注释(易引起字符集问题)

确认编译器支持//

/*之后有空格, */之前有空格

1.2.1 好的注释

法律、版权信息

# /* **************************************************************************

# * *

# * (C) Copyright Paul Mensonides 2002.

# * Distributed under the Boost Software License, Version 1.0. (See

# * accompanying file LICENSE_1_0.txt or copy at

# * http://www.boost.org/LICENSE_1_0.txt)

# * *

# ************************************************************************** */

#

# /* See http://www.boost.org for most recent version. */

#

# ifndef BOOST_PREPROCESSOR_SEQ_FOR_EACH_HPP

# define BOOST_PREPROCESSOR_SEQ_FOR_EACH_HPP

#

# include

# include

# include

# include

# include

# include

# include

#

陷阱、警示

#if (defined(BOOST_MSVC) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && _MSC_VER >= 1300

//

// MSVC supports types which have alignments greater than the normal

// maximum: these are used for example in the types __m64 and __m128

// to provide types with alignment requirements which match the SSE

// registers. Therefore we extend type_with_alignment<> to support

// such types, however, we have to be careful to use a builtin type

// whenever possible otherwise we break previously working code:

// see http://article.gmane.org/gmane.comp.lib.boost.devel/173011

// for an example and test case. Thus types like a8 below will

// be used *only* if the existing implementation can't provide a type

// with suitable alignment. This does mean however, that type_with_alignment<>

// may return a type which cannot be passed through a function call

// by value (and neither can any type containing such a type like

// Boost.Optional). However, this only happens when we have no choice

// in the matter because no other "ordinary" type is available.

//

意图解释

// Borland specific version, we have this for two reasons:

// 1) The version above doesn't always compile (with the new test cases for example)

// 2) Because of Borlands #pragma option we can create types with alignments that are

// greater that the largest aligned builtin type.

namespace align

{

#pragma option push -a16

struct a2{ short s; };

struct a4{ int s; };

struct a8{ double s; };

struct a16{ long double s; };

#pragma option pop

}

性能优化代码

// Fast version of "hash = (65599 * hash) + c"

hash = (hash << 6) + (hash << 16) - hash + c;

不易理解代码

// kk::mm::ss, MM dd, yyyy

std::string timePattern = "\\d{2}:\\d{2}:\\d{2}, \\d{2} \\d{2}, \\d{4}";

1.2.2 不好的注释

日志型注释 -> 删除,使用源码管理工具记录

反例:

/**

*c00kiemon5ter 2015-9-20 add SquareState

* c00kiemon5ter 2015-10-1 change the symbol

*/

public enum SquareState {

BLACK('●'),

WHITE('○'),

// BLACK('x'),

// WHITE('o'),

PSSBL('.'),

EMPTY(' ');

private final char symbol;

SquareState(char symbol) {

this.symbol = symbol;

}

public char symbol() {

return this.symbol;

}

}

正例:

public enum SquareState {

BLACK('●'),

WHITE('○'),

PSSBL('.'),

EMPTY(' ');

private final char symbol;

SquareState(char symbol) {

this.symbol = symbol;

}

public char symbol() {

return this.symbol;

}

}

$git commit -m "change BLACK symbol from x to ●, WHITE from ○ to O"

归属、签名 -> 删除,源码管理工具自动记录

反例:

/**

* @author c00kiemon5ter

*/

public enum Player {

BLACK(SquareState.BLACK),

WHITE(SquareState.WHITE);

...

}

正例:

public enum Player {

BLACK(SquareState.BLACK),

WHITE(SquareState.WHITE);

...

}

$git config --global user.name c00kiemon5ter

注释掉的代码 -> 删除,使用源码管理工具保存

反例:

public Point evalMove() {

AbstractSearcher searcher;

Evaluation evalfunc;

searcher = new NegaMax();

//evalfunc = new ScoreEval();

evalfunc = new ScoreDiffEval();

//evalfunc = new ScoreCornerWeightEval();

return searcher.simpleSearch(board, player, depth, evalfunc).getPoint();

}

正例:

public Point evalMove() {

AbstractSearcher searcher;

Evaluation evalfunc;

searcher = new NegaMax();

evalfunc = new ScoreDiffEval();

return searcher.simpleSearch(board, player, depth, evalfunc).getPoint();

}

函数头 -> 尝试使用更好的函数名,更好参数名,更少参数替换注释

反例:

/***********************************************************************

* function Name: GetCharge

* function description:get total Rental charge

* return value:WORD32

* other

* date version author contents

* -----------------------------------------------

* 2014/11/28 V1.0 XXXX XXXX

*************************************************************************/

WORD32 GetCharge(T_Customer* tCustomer)

{

...

}

正例:

WORD32 GetTotalRentalCharge(Customer* customer)

{

...

}

位置标记 -> 删除,简化逻辑

反例:

double getPayAmount(){

double result;

if(isDead){

result = deadAmount();

}

else{//!isDead

if(isSeparated){

result = separatedAmount();

}

else{ //!isSeparated && !//!isDead

if(isRetired){

result = retiredAmount();

}

else{ //!isSeparated && !//!isDead && !isRetired

result = normalPayAmount();

}

}

}

return result;

}

正例:

double getPayAmount(){

if(isDead) return deadAmount();

if(isSeparated) return separatedAmount();

if(isRetired) return retiredAmount();

return normalPayAmount();

}

过时、误导性注释 -> 删除

反例:

// Utility method that returns when this.closed is true. Throws an exception

// if the timeout is reached.

public synchronized void waitForClose(final long timeoutMillis) throws Exception

{

if(!closed)

{

wait(timeoutMillis);

if(!closed)

throw new Exception("MockResponseSender could not be closed");

}

}

正例:

public synchronized void waitForClose(final long timeoutMillis) throws Exception

{

if(!closed)

{

wait(timeoutMillis);

if(!closed)

throw new Exception("MockResponseSender could not be closed");

}

}

多余、废话注释 -> 删除

反例:

class GTEST_API_ AssertionResult

{

public:

// Copy constructor.

// Used in EXPECT_TRUE/FALSE(assertion_result).

AssertionResult(const AssertionResult& other);

// Used in the EXPECT_TRUE/FALSE(bool_expression).

explicit AssertionResult(bool success) : success_(success) {}

// Returns true iff the assertion succeeded.

operator bool() const { return success_; } // NOLINT

private:

// Stores result of the assertion predicate.

bool success_;

};

正例:

class GTEST_API_ AssertionResult

{

public:

AssertionResult(const AssertionResult& other);

explicit AssertionResult(bool success) : success_(success) {}

operator bool() const { return success_; }

private:

bool success_;

};

1.3 物理设计

遵循原则

头文件编译自满足(C/C++)

文件职责单一

文件最小依赖

文件信息隐藏

注意事项:

包含文件时,确保路径名、文件名大小写敏感

文件路径分隔符使用/,不使用\

路径名一律使用小写、下划线(_)或中划线风格(-)

文件名与程序实体名称一致

1.3.1 头文件编译自满足(C/C++)

对于C/C++语言头文件编译自满足,即头文件可以单独编译成功。

反例:

#ifndef _INCL_POSITION_H_

#define _INCL_POSITION_H_

#include "base/Role.h"

struct Position : Coordinate, Orientation

{

Position(int x, int y, int z, const Orientation& d);

bool operator==(const Position& rhs) const;

IMPL_ROLE(Coordinate);

IMPL_ROLE(Orientation);

};

#endif

正例:

#ifndef _INCL_POSITION_H_

#define _INCL_POSITION_H_

#include "Coordinate.h"

#include "Orientation.h"

#include "base/Role.h"

struct Position : Coordinate, Orientation

{

Position(int x, int y, int z, const Orientation& d);

bool operator==(const Position& rhs) const;

IMPL_ROLE(Coordinate);

IMPL_ROLE(Orientation);

};

#endif

1.3.2 文件设计职责单一

文件设计职责单一,是指文件中对于对于用户公开的信息,应该是一个概念,避免把不相关的概念糅合在一个文件中,文件间增加不必要的依赖

反例:

UnmannedAircraft.h

#ifndef _INCL_UNMANNED_AIRCRAFT_H_

#define _INCL_UNMANNED_AIRCRAFT_H_

#include "Coordinate.h"

#include "Orientation.h"

#include "base/Role.h"

struct Instruction;

struct Position : Coordinate, Orientation

{

Position(int x, int y, int z, const Orientation& d);

bool operator==(const Position& rhs) const;

IMPL_ROLE(Coordinate);

IMPL_ROLE(Orientation);

};

struct UnmannedAircraft

{

UnmannedAircraft();

void on(const Instruction&);

const Position& getPosition() const;

private:

Position position;

};

#endif

正例:

Position.h

#ifndef _INCL_POSITION_H_

#define _INCL_POSITION_H_

#include "Coordinate.h"

#include "Orientation.h"

#include "base/Role.h"

struct Position : Coordinate, Orientation

{

Position(int x, int y, int z, const Orientation& d);

bool operator==(const Position& rhs) const;

IMPL_ROLE(Coordinate);

IMPL_ROLE(Orientation);

};

#endif

UnmannedAircraft.h

#ifndef _INCL_UNMANNED_AIRCRAFT_H_

#define _INCL_UNMANNED_AIRCRAFT_H_

#include "Position.h"

struct Instruction;

struct UnmannedAircraft

{

UnmannedAircraft();

void on(const Instruction&);

const Position& getPosition() const;

private:

Position position;

};

#endif

1.3.3 仅包含需要的文件

文件设计时,应遵循最小依赖原则,仅包含必须的文件即可。

反例:

#ifndef _INCL_UNMANNED_AIRCRAFT_H_

#define _INCL_UNMANNED_AIRCRAFT_H_

#include "Position.h"

#include "Orientation.h"

#include "Coordinate.h"

#include "Instruction.h"

struct UnmannedAircraft

{

UnmannedAircraft();

void on(const Instruction&);

const Position& getPosition() const;

private:

Position position;

};

#endif

正例:

#ifndef _INCL_UNMANNED_AIRCRAFT_H_

#define _INCL_UNMANNED_AIRCRAFT_H_

#include "Position.h"

struct Instruction;

struct UnmannedAircraft

{

UnmannedAircraft();

void on(const Instruction&);

const Position& getPosition() const;

private:

Position position;

};

#endif

特别的,对于C++而言,可以使用类或者结构体前置声明,而不包含头文件,降低编译依赖。该类依赖被称为弱依赖,编译时不需要知道实体的真实大小,仅提供一个符号即可,主要有:

指针

引用

返回值

函数参数

反例:

#ifndef _INCL_INSTRUCTION_H_

#define _INCL_INSTRUCTION_H_

#include "Coordinate.h"

#include "Orientation.h"

struct Instruction

{

virtual void exec(Coordinate&, Orientation&) const = 0;

virtual ~Instruction() {}

};

#endif

正例:

#ifndef _INCL_INSTRUCTION_H_

#define _INCL_INSTRUCTION_H_

struct Coordinate;

struct Orientation;

struct Instruction

{

virtual void exec(Coordinate&, Orientation&) const = 0;

virtual ~Instruction() {}

};

#endif

1.3.4 仅公开用户需要的接口

文件设计时,应遵循信息隐藏原则,仅公开用户需要的接口,对于其他信息尽量隐藏,以减少不必要的依赖。 特别的,对于C语言头文件中仅公开用户需要接口,其他函数隐藏在源文件中。

反例:

struct RepeatableInstruction : Instruction

{

RepeatableInstruction(const Instruction&, int n);

virtual void exec(Coordinate&, Orientation&) const;

bool isOutOfBound() const;

private:

const Instruction& ins;

const int n;

};

正例:

struct RepeatableInstruction : Instruction

{

RepeatableInstruction(const Instruction&, int n);

private:

virtual void exec(Coordinate&, Orientation&) const;

bool isOutOfBound() const;

private:

const Instruction& ins;

const int n;

};

特别的,对于C可以使用static对编译单元中全局变量、函数等进行隐藏,对于支持面向对象语言则使用其封装特性即可。

反例:

BOOLEAN isGbr(BYTE qci)

{

return qci >= 1 && qci <= 4;

}

BOOLEAN isGbrBitRateValid(const GbrIE* gbrIE)

{

ASSERT_VALID_PTR_BOOL(gbrIE);

return gbrIE->dlGbr <= gbrIE->dlMbr &&

gbrIE->ulGbr <= gbrIE->ulMbr;

}

BOOLEAN isGbrIEValid(const QosPara* qosPara)

{

if(!isGbr(qosPara->qci)) return TRUE;

if(qosPara->grbIEPresent == 0) return TRUE;

return isGbrBitRateValid(&qosPara->gbrIE);

}

正例:

static BOOLEAN isGbr(BYTE qci)

{

return qci >= 1 && qci <= 4;

}

static BOOLEAN isGbrBitRateValid(const GbrIE* gbrIE)

{

ASSERT_VALID_PTR_BOOL(gbrIE);

return gbrIE->dlGbr <= gbrIE->dlMbr &&

gbrIE->ulGbr <= gbrIE->ulMbr;

}

BOOLEAN isGbrIEValid(const QosPara* qosPara)

{

if(!isGbr(qosPara->qci)) return TRUE;

if(qosPara->grbIEPresent == 0) return TRUE;

return isGbrBitRateValid(&qosPara->gbrIE);

}

参考文献:

Robert C.Martin-代码整洁之道 ↩ ↩

刘光聪-cpp programming style ↩

引用\[1\]和\[2\]提到,当使用mysql命令时报错"Can't connect to MySQL server on localhost (10061)"或者使用"net start mysql"命令时报错"服务名无效",通常是因为mysql服务没有启动。因此,第一步应该是检查mysql服务是否已经启动。可以以管理员身份运行cmd.exe,然后输入"net start mysql"来启动mysql服务。如果服务已经启动,但仍然无法连接到MySQL服务器,可能是其他原因导致的。 引用\[3\]提到,有时候重启服务器后仍然出现MySQL 'localhost' (10061)错误。这可能不是由于数据库链接打开过多导致的,而是其他问题。为了解决这个问题,可以在网上查找解决方法,或者尝试重新安装MySQL服务器。 综上所述,当出现"Can't connect to MySQL server on localhost (10061)"错误时,首先应该检查mysql服务是否已经启动。如果服务已经启动但仍然无法连接,可能是其他问题导致的,可以尝试查找解决方法或重新安装MySQL服务器。 #### 引用[.reference_title] - *1* *3* [Can‘‘t connect to MySQL server on localhost (10061)解决方法](https://blog.youkuaiyun.com/jxnuzhouguohong/article/details/129024243)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [can‘t connect to mysql server on localhost解决办法。 net start mysql——无法启动服务,原因可能是已...](https://blog.youkuaiyun.com/m0_72084056/article/details/126418662)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值