结合工程实践的选题,我选择的是一个开源的C++轻量级网络框架——ZLToolKit。下面按照所给的要求依次展开(如下均以Google的C++编码规范为标准):mysql
1.根据其编程语言或项目特色,分析其在源代码目录结构、文件名/类名/函数名/变量名等命名、接口定义规范和单元测试组织形式等方面的作法和特色算法
src文件夹下的源代码目录结构以下:
sql
src | |-- NetWork # 网络模块 | |-- Socket.cpp # 套接字抽象封装,包含了TCP服务器/客户端,UDP套接字 | |-- Socket.h | |-- sockutil.cpp # 系统网络相关API的统一封装 | |-- sockutil.h | |-- TcpClient.cpp # TCP客户端封装,派生该类能够很容易实现客户端程序 | |-- TcpClient.h | |-- TcpLimitedSession.h # 派生于TcpSession,该模板类能够全局限制会话数量 | |-- TcpServer.h # TCP服务器模板类,能够很容易就实现一个高性能私有协议服务器 | |-- TcpSession.h # TCP服务私有协议实现会话基类,用于处理TCP长链接数据及响应 | |-- Poller # 主线程事件轮询模块 | |-- EventPoller.cpp # 主线程,全部网络事件由此线程轮询并触发 | |-- EventPoller.h | |-- Pipe.cpp # 管道的对象封装 | |-- Pipe.h | |-- PipeWrap.cpp # 管道的包装,windows下由socket模拟 | |-- SelectWrap.cpp # select 模型的简单包装 | |-- SelectWrap.h | |-- Timer.cpp # 在主线程触发的定时器 | |-- Timer.h | |-- Thread # 线程模块 | |-- AsyncTaskThread.cpp # 后台异步任务线程,能够提交一个可定时重复的任务后台执行 | |-- AsyncTaskThread.h | |-- rwmutex.h # 读写锁,实验性质的 | |-- semaphore.h # 信号量,由条件变量实现 | |-- spin_mutex.h # 自旋锁,在低延时临界区适用,单核/低性能设备慎用 | |-- TaskQueue.h # functional的任务列队 | |-- threadgroup.h # 线程组,移植自boost | |-- ThreadPool.h # 线程池,能够输入functional任务至后台线程执行 | |-- WorkThreadPool.cpp # 获取一个可用的线程池(能够加入线程负载均衡分配算法) | |-- WorkThreadPool.h | |-- Util # 工具模块 |-- File.cpp # 文件/目录操做模块 |-- File.h |-- function_traits.h # 函数、lambda转functional |-- logger.h # 日志模块 |-- MD5.cpp # md5加密模块 |-- MD5.h |-- mini.h # ini配置文件读写模块,支持unix/windows格式的回车符 |-- NoticeCenter.h # 消息广播器,能够广播传递任意个数任意类型参数 |-- onceToken.h # 使用RAII模式实现,能够在对象构造和析构时执行一段代码 |-- ResourcePool.h # 基于智能指针实现的一个循环池,不须要手动回收对象 |-- RingBuffer.h # 环形缓冲,能够自适应大小,适用于GOP缓存等 |-- SqlConnection.cpp # mysql客户端 |-- SqlConnection.h |-- SqlPool.h # mysql链接池,以及简单易用的sql语句生成工具 |-- SSLBox.cpp # openssl的黑盒封装,屏蔽了ssl握手细节,支持多线程 |-- SSLBox.h |-- TimeTicker.h # 计时器,能够用于统计函数执行时间 |-- util.cpp # 其余一些工具代码,适配了多种系统 |-- util.h |-- uv_errno.cpp # 提取自libuv的错误代码系统,主要是为了兼容windows |-- uv_errno.h
能够看到,源码的模块划分主要以原做者设计实现时的功能模块划分为导向。
文件名:按照Google的C++编码标准,文件名应当所有使用小写。而该源码文件命名较为随意,一些采用大写,一些采用小写,不符合规范要求
类型名:按照Google的C++编码标准,类型命名应当每一个单词首字母大写,不含下划线,以名词形式,且全部类型命名 —— 类, 结构体, 类型定义 (typedef
), 枚举等均使用相同约定。
该源码一些类型的代码以下所示,能够看出类型命名基本依照现有的标准。
typedef
class SocketFlags{ public: SocketFlags(int flags):_flags(flags){}; ~SocketFlags(){} int _flags; }; class MutexWrapper { public: MutexWrapper(bool enable){ _enable = enable; } ~MutexWrapper(){} inline void lock(){ if(_enable){ _mtx.lock(); } } inline void unlock(){ if(_enable){ _mtx.unlock(); } } private: bool _enable; Mtx _mtx; }; typedef enum { Err_success = 0, //成功 Err_eof, //eof Err_timeout, //超时 Err_refused,//链接别拒绝 Err_dns,//dns解析失败 Err_shutdown,//主动关闭 Err_other = 0xFF,//其余错误 } ErrCode;
函数名:按照标准,常规函数每一个单词首字母大写,使用命令式语气,好比:OpenFile() CheckFileName(),而存取函数或短小的内联函数使用小写加下 划线,且与访问变量相吻合,好比 set_num_errors()。该源码的部分函数声明或调用以下:编程
void Socket::setOnErr(const onErrCB &cb); void Socket::setOnAccept(const onAcceptCB &cb); void Socket::setOnFlush(const onFlush &cb); //设置Socket生成拦截器 void Socket::setOnBeforeAccept(const onBeforeAcceptCB &cb);
setsockopt(sockFd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&imr, sizeof (struct ip_mreq));
能够看到,该源码中函数的命名主要依据的时驼峰式的命名法,但并未统一,时而依照驼峰命名法,时而所有小写,不符合标准。windows
变量名:按照标准,变量名一概小写,单词用下划线相连,例如:int player_id; string table_name;特殊的是类成员变量,后跟下划线区别普通变量,比 player_name_ player_id_。该源码的变量命名基本按照了小写的要求,类中的变量命名也经过下划线与普通变量区别开来:缓存
class SockException: public std::exception { public: SockException(ErrCode errCode = Err_success, const string &errMsg = "", int customCode = 0) { _errMsg = errMsg; _errCode = errCode; _customCode = customCode; } //重置错误 void reset(ErrCode errCode, const string &errMsg) { _errMsg = errMsg; _errCode = errCode; } //错误提示 virtual const char* what() const noexcept { return _errMsg.c_str(); } //错误代码 ErrCode getErrCode() const { return _errCode; } //判断是否真的有错 operator bool() const{ return _errCode != Err_success; } //用户自定义错误代码 int getCustomCode () const{ return _customCode; } //获取用户自定义错误代码 void setCustomCode(int code) { _customCode = code; }; private: string _errMsg; ErrCode _errCode; int _customCode = 0; };
2.列举哪些作法符合代码规范和风格通常要求 服务器
根据上面的分析,咱们能够看出:网络
2.1 该源码文件名的命名规则不符合Google的C++标准中规定的——文件名应当所有使用小写。
多线程
2.2 该源码的类型名的命名规则基本符合Google的C++标准中规定的——类型命名应当每一个单词首字母大写,不含下划线,以名词形式,且全部类型命名 —— 类, 结构体, 类型定义 (
apptypedef
), 枚举等均使用相同约定。
2.3 该源码函数的命名不符合一致性的要求
2.4 该源码变量名基本符合Google的C++标准
3.列举哪些作法有悖于“代码的简洁、清晰、无歧义”的基本原则,及如何进一步优化改进
1.源码总体注释较少,远低于注释要占代码20%的要求,尤为是对宏的注释,基本没有。改进:添加注释——每一条宏都要加注释;在函数定义的开头添加注释以说明该函数的做用
2.源码中部分使用了宏定义函数,这是C++不提倡的作法。改进:使用内联函数代替宏函数
4.总结同类编程语言或项目在代码规范和风格的通常要求
代码风格因人而异,最重要的是保持本身代码风格从一而终的一致性。但无可厚非,有一些出自大厂的且你们都承认代码风格规范是值得借鉴和学习的,由于它符 合大多数人的阅读习惯,如下根据相关代码规范对代码的基本书写列出一些通常要求:
1.命名:
文件名所有小写;函数名所有按照单词首字母大写;普通变量名一概小写;成员变量名小写且以_为结束做为标记。
2.空行
定义变量后要空行
每一个函数定义结束以后都要加空行
两个相对独立的程序块之间要空行
3.空格
函数名以后不要留空格
(
向后紧跟;)
、,
、;
这三个向前紧跟;紧跟处不留空格
值运算符、关系运算符、算术运算符、逻辑运算符、位运算符等先后应当加空格
单目运算符先后不加空格
4.缩进
若是地位相等,则不须要缩进;若是属于某一个代码的内部代码就须要缩进。
5.注释
注意注释的数量,注释太多会让人眼花缭乱
当代码比较长,特别是有多重嵌套的时候,应当在段落的结束处加注释
每一条宏定义的右边必需要有注释,说明其做用