PhyStar程序规范¶
规范制定人¶
崔智文 2022/06/13
C++程序标准¶
C++ 标准:为了长远考虑,尽可能以c++-20标准作为基础。由于历史代码的兼容性,代码书写不要超过c++-20的标准范围
一些推荐的特性:(后期补充)
以下内容仅为约定,具体内容将随PhyStar的开发进行更改
基本数据类型¶
别名¶
浮点数:统一用”Real” 代替浮点数,在头文件添加,利用相关宏命令进行区分
#ifdef D_FLOAT
using Real = float; //对应fortran kind =4
#else
using Real = double;//对应fortran kind =8
#endif
整型:(暂定)
using Int = int; //对应fortran kind =4 using Intl = long long; //对应fortran kind =8 using uInt = unsigned int; using uIntl = unsigned long long;
复数
using Complex = std::complex<Real>;//单双精度由Real 决定
使用其他开源软件中,未被允许的基本数据类型别名,需要在使用前用注释说明别名定义
常量¶
数学常量:全部大写,
可使用c++/c 标准自带的,cmath 或math.h, 需要在#include前定义宏变量#define _USE_MATH_DEFINES
#define _USE_MATH_DEFINES // for C++ #include <cmath> #define _USE_MATH_DEFINES // for C #include <math.h>
符号
表达式
值
M_Ee
2.71828182845904523536
M_LOG2Elog2(e)
1.44269504088896340736
M_LOG10Elog10(e)
0.434294481903251827651
M_LN2ln(2)
0.693147180559945309417
M_LN10ln(10)
2.30258509299404568402
M_PIpi
3.14159265358979323846
M_PI_2pi/2
1.57079632679489661923
M_PI_4pi/4
0.785398163397448309616
M_1_PI1/pi
0.318309886183790671538
M_2_PI2/pi
0.636619772367581343076
M_2_SQRTPI2/sqrt(pi)
1.12837916709551257390
M_SQRT2sqrt(2)
1.41421356237309504880
M_SQRT1_21/sqrt(2)
0.707106781186547524401
也可以自定义常量(自定义时用static const 关键字,不要使用宏命令,并用namespace 限定作用域)
namespace constant{ static const auto PI=3.14159265358979323846; }
枚举中的常量:用k前缀,命名用驼峰命名规则
enum{ kSphere=0, kSphereOseen };
枚举类中的常量:用驼峰命名即可
enum class PartType{ Sphere=0, SphereOseen };
自定义基本数据类型(blitz)¶
#include "blitz/array.h"
template <typename T,int N>
using Array = blitz::Array<T,N>;
using Array4r = blitz:: Array<Real, 4>; //
using Array3r = blitz:: Array<Real, 3>; //
using Array2r = blitz:: Array<Real, 2>;
using Array1r = blitz:: Array<Real, 1>;
using Array4i = blitz::Array<int, 4>;
using Array3i = blitz::Array<int, 3>;
using Array2i = blitz::Array<int, 2>;
using Array1i = blitz::Array<int, 1>;
using Array4cr = blitz::Array<std::complex<Real>, 4>;
using Array3cr = blitz::Array<std::complex<Real>, 3>;
using Array2cr = blitz::Array<std::complex<Real>, 2>;
using Array1cr = blitz::Array<std::complex<Real>, 1>;
using Vec1r = blitz::TinyVector<Real, 1>;
using Vec2r = blitz::TinyVector<Real, 2>;
using Vec3r = blitz::TinyVector<Real, 3>;
using Vec4r = blitz::TinyVector<Real, 4>;
using Vec1i = blitz::TinyVector<int, 1>;
using Vec2i = blitz::TinyVector<int, 2>;
using Vec3i = blitz::TinyVector<int, 3>;
using Vec4i = blitz::TinyVector<int, 4>;
using Vec2cr = blitz::TinyVector<std::complex<Real>, 2>;
using Vec3cr = blitz::TinyVector<std::complex<Real>, 3>;
using Vec4cr = blitz::TinyVector<std::complex<Real>, 4>;
using Mat4r = blitz::TinyMatrix<Real, 4, 4>;
using Mat3r = blitz::TinyMatrix<Real, 3, 3>;
using Mat2r = blitz::TinyMatrix<Real, 2, 2>;
//template
template <typename T>
using Array1 = blitz::Array<T, 1>;
template <typename T>
using Array2 = blitz::Array<T, 2>;
template <typename T>
using Array3 = blitz::Array<T, 3>;
template <typename T>
using Vec1 = blitz::TinyVector<T, 1>;
template <typename T>
using Vec2 = blitz::TinyVector<T, 2>;
template <typename T>
using Vec3 = blitz::TinyVector<T, 3>;
template <typename T>
using Vec4 = blitz::TinyVector<T, 4>;
template <typename T>
using Mat2 = blitz::TinyMatrix<T, 2, 2>;
template <typename T>
using Mat3 = blitz::TinyMatrix<T, 3, 3>;
template <int dim>
using Arrayr = blitz::Array<Real, dim>;
template <int dim>
using Arrayi = blitz::Array<int, dim>;
template <int dim>
using Arraycr = blitz::Array<std::complex<Real>, dim>;
template <int length>
using Veci = blitz::TinyVector<int,length>;
template <int length>
using Vecr = blitz::TinyVector<Real, length>;
template <int length>
using Veccr = blitz::TinyVector<std::complex<Real>, length>;
template <typename T,int length>
using Vec = blitz::TinyVector<T, length>;
template <int length>
using Mati = blitz::TinyMatrix<int,length,length>;
template <int length>
using Matr = blitz::TinyMatrix<Real, length,length>;
template <int length>
using Matcr = blitz::TinyMatrix<std::complex<Real>, length,length>;
template <typename T,int length>
using Mat = blitz::TinyMatrix<T, length,length>;
命名规则¶
变量¶
普通变量,结构体内和类中的public 成员变量:统一使用小写,尽量含义清晰。对于局部变量、临时变量,尽可能用易识别的缩写,避免单词组合;对于结构体/类内的成员变量,尽可能表达内容清晰,完整,如需多单词组合,用下划线区分**(不宜超过三个单词/两个下划线)**,如需使用缩写,请尽量用常见的缩写。
% 局部,临时变量 Int dim; Real ar; // aspect ratio, Real lam; // Lambda =(ar*ar-1.)/(ar*ar+1) Real dr; // density ratio % 结构体/类内成员变量 Int idim; Real aspect_ratio; Real lam; // lambda Real ulam; // Lambda , up lambda Real density_ratio; Real radius; Real diameter;
私有变量,private, 统一小写,且在变量名前使用下划线
Real _data; Real _comm; Real _aspect_ratio;
指针:统一用ptr_前缀,对于局部和临时的指针变量,在不引入歧义时,用p前缀, 下划线在不引起歧义时可略去
Real* ptr_particle; Real* ptr_field; //对于局部或临时指针变量 Real* p_particle; Real* pfield;
类/结构体,函数名¶
采用驼峰命名,在非必须,不要使用下划线。
class BlockCart;
class FluidData;
void InterpLag2Cart(...);
Real vSolver();
类中私有函数成员,也采用驼峰命名,在函数名前加下划线
void _Foo(); int _FooTest();
类/结构体中,用于设置和取值的成员函数,采用小驼峰命名规则
void setNum(int num); int getNum(); int& refNum();
代码文件命名名¶
采用大驼峰命名,非必要不使用下划线;
头文件以“.h ”为后缀
模板文件以“.hpp” 为后缀
模板文件的补充“.hxx” 为后缀
c++程序定义文件以”.cpp”为后缀
“.h”与“.hpp”, “.hxx”后缀的文件放到include文件夹,”.cpp”后缀的文件放入src文件夹
Mesh.hpp
CartMesh.hpp
PointParticle.h
ParticleBase.h
ParticleBase.cpp
TimeScheme_Static.hpp //当单词组合较多时,可用下划线突出需要强调的部分,以方便识别
注释约定¶
使用doxygen 注释规范,方便后面生成api文档
尽可能用简洁的英文,注释。部分难以用英文注释的,可用中文注释,但要尽可能避免中文注释,因为中文注释在跨平台和软件中易出现乱码。
变量注释: 在变量声明后,用//开始注释
函数注释:在函数前注释,简明用途,输入/输出接口,函数头和函数定义处保持一样
结构体/类注释:在结构体/类前注释,说明类名,用途,其他说明t
文件注释: 在文件头进行注释,说明文件主要内容,作者,版权声明等
节/模块注释:程序中对某一块功能的主要功能进行必要说明
代码习惯¶
循环¶
循环体必加花括号,左括号跟在条件语句后, 右括号与for 对齐
使用++i 代替i++; 同理,用–i代替i–;
变量定义尽可能在循环体外,可以加快运行速度,和避免编译器优化问题。
int sum=0;
for(int i=0;i<N;++i){
sum+=i;
}
多重循环,缩进关系,表现出层次关系。
若循环体过长,需要在右括号后添加相关注释,以标明不同层循环体的结束
数组统一采用C风格的行优先策略,因此,在循环中从外到内分别为i,j,k
Array3i a(10,10,10);
a=10;
int sum=0;
for(int i=0; i<10; ++i){
for(int j=0;j<10;++j){
for(int k=0;k<10;++k){
sum+=a(i,j,k);
... //其他内容
}//end of k
...//其他内容
}// end of j
...//其他内容
}// end of i
函数¶
函数中的参数,尽可能使用引用,恰当使用指针,尽可能不给参数赋默认值
函数定义的函数体,左花括号跟在函数名参数列表后,右括号与函数名对齐
void Foo(int a){
a=1;
}
const 限定词¶
几种需要加const的情况
常量
函数传参:若传的参数只使用,不修改
其它必要情况
new 与delete配合使用¶
一个函数体内,使用new申请了空间,就必须要用delete释放
在类的构造或者其他成员函数中存在类成员变量的new, 就一定需要在析构函数中释放空间
释放空间前,请务必判断指针指定的空间是否申请。
指针¶
空指针,一律用nullptr 赋值,避免野指针
auto¶
尽可能少用auto推断,只在引用,c++自带数据类型进行推段,其余时候不做推断处理,可避免一些优化错误
Vec3r a=1.;
Vec3r b=2.;
auto c=a+b;// 不推荐,有可能出推断错误,auto不是Vec3r
auto& d=a; //可以推断引用
auto f=1 + 1; //可以推断c++自带类型
编译¶
在linux系统中使用cmake 进行编译。windows系统可用wsl或者虚拟机编译。