Compare commits

..

39 Commits

Author SHA1 Message Date
9a540ba114 更新 办公室文件共享.md 2024-08-18 15:54:22 +08:00
a462997aba Merge branch 'main' of http://192.168.1.11:7777/gnibuoz/wiki into main 2024-08-18 11:44:23 +08:00
75f601f053 01.添加目录
02.添加公网访问内容
2024-08-18 11:43:46 +08:00
d31f971874 标题
第一行
第二行
第三行
2024-08-03 11:49:52 +08:00
11bafbc6eb 测试提交标题
测试提交内容
01.第一行
02.第二行
2024-08-03 11:47:38 +08:00
d8febd67cf 测试提交标题
测试提交内容
01.第一行
02.第二行
2024-08-03 11:44:31 +08:00
69627b61ad 概要信息
补充信息:
01.第一行
02.第二行
2024-08-03 11:24:53 +08:00
a5f45aff17 更新 README.md 2024-08-03 11:14:26 +08:00
995f5d8b99 更新 README.md 2024-08-03 11:09:38 +08:00
99682762e5 更新 README.md 2024-08-03 11:05:45 +08:00
391b7353f3 revert b8220e9aaf
revert 更新 README.md
2024-08-03 10:42:11 +08:00
b8220e9aaf 更新 README.md 2024-08-03 10:22:17 +08:00
5a4e55d527 更新 README.md 2024-08-03 10:10:13 +08:00
de9f09e369 更新 README.md 2024-08-03 10:05:00 +08:00
01c1882ea0 添加好用的资源分享页面 2024-07-20 17:28:50 +08:00
fe961b1421 修订格式及部分示例 2024-07-16 19:11:04 +08:00
5ec2e64021 修复代码片段高亮 2024-07-15 18:10:07 +08:00
b34028f8bf 移除原仓库链接 2024-07-15 16:44:55 +08:00
8d82385299 修正目录索引 2024-07-15 16:42:46 +08:00
08ad7783fe 修正目录索引错误 2024-07-15 16:41:35 +08:00
8e7550bfee 添加LLVM代码规范和Qt代码规范 2024-07-15 16:35:05 +08:00
f7cbd0f1d1 基于Qt编码规范,修改部分规范,并调整对应示例 2024-07-15 16:33:48 +08:00
c42c006b9a 修复缩进及高亮 2024-07-15 15:33:18 +08:00
e033bc8291 修复代码高亮 2024-07-15 15:32:29 +08:00
b3c844ba2d 修复格式及部分缩进 2024-07-15 15:31:24 +08:00
e000cd71d2 首次提交,当前状态为Qt编码规范 2024-07-15 15:25:08 +08:00
a7ea4e35bd 创建Qt编译文章 2024-07-15 11:46:05 +08:00
439a8c9a80 由于Gitea的markdown目前不支持TOC自动目录语法,修改为使用Visual Studio Code插件【Markdown All in One】自动生成目录,使用方法为(注意得先安装该插件):
01. 将光标调整至需要生成目录的地方
02. 按下[Ctrl+Shift+P]快捷键,输入[Markdown All in One: Create Table of Contents],然后回车执行即可
2024-07-15 11:16:14 +08:00
dd9dc480fa 添加目录 2024-07-15 11:06:30 +08:00
2b6ad265a6 格式修订 2024-07-15 11:03:31 +08:00
57b98b7f2d 修订格式及部分内容 2024-07-15 11:01:41 +08:00
fe3be0a3a0 修复部分格式错误 2024-07-14 17:09:55 +08:00
a8b48821f9 新增VCPKG编译错误及其处理方法 2024-07-14 17:06:27 +08:00
841f5ac800 修复附件链接 2024-05-31 16:56:41 +08:00
ab85d05e51 修复附件链接 2024-05-31 16:53:01 +08:00
193f52f86d 添加osgEarth创建六边形网格文章 2024-05-31 16:50:44 +08:00
5706f8c05a 修正目录错误 2024-05-13 15:29:33 +08:00
786d2a91db 图片添加超链接 2024-05-13 15:28:13 +08:00
264828fc3a 添加换行,避免图文同行 2024-05-13 15:23:13 +08:00
14 changed files with 2839 additions and 6 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vscode/settings.json

View File

@ -0,0 +1,61 @@
# RK3588实机编译Qt5.15.13
## 目录
- [RK3588实机编译Qt5.15.13](#rk3588实机编译qt51513)
- [目录](#目录)
- [一、准备工作](#一准备工作)
- [二、编译安装](#二编译安装)
- [2.1 配置Qt(configure)](#21-配置qtconfigure)
- [2.2 编译](#22-编译)
- [2.3 安装](#23-安装)
- [附录A常见编译错误](#附录a常见编译错误)
- [1. QBasicMutex::lockInternal(int)重定义](#1-qbasicmutexlockinternalint重定义)
## 一、准备工作
- 下载Qt源码包本文以5.15.13为例如需编译其它版本下载对应版本的源代码即可注意版本不同时命令中的版本号与实际版本同步下载Qt源码包[Qt5.15.13源码链接](https://download.qt.io/archive/qt/5.15/5.15.13/single/)
- 通过以下命令行解压源代码至编译目录(需足够的磁盘空间,一般在用户目录新建)
> sudo xz -d qt-everywhere-src-5.15.13.tar.xz
> sudo tar -xvf qt-everywhere-src-5.15.13.tar
- 安装编译环境
> sudo apt-get install build-essential perl python git
- 安装依赖库
> sudo apt-get install libx11-*
> sudo apt-get install libx11*
>
> sudo apt-get install libxcb-*
> sudo apt-get install libxcb*
>
> sudo apt-get install libxkbcommon-dev
> sudo apt-get install libxkbcommon-x11-dev
> sudo apt-get install libxcb-xinerama0
> sudo apt-get install '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev
## 二、编译安装
### 2.1 配置Qt(configure)
切换至解压出来的Qt目录中运行以下命令如果权限不足使用sudo执行注意其中的-prefix参数为最终Qt库的安装目录/home/firefly/Qt5.15.13),应根据实际环境进行修改,在命令行中执行修改后的命令:
> ./configure -prefix /home/firefly/Qt5.15.13 -confirm-license -opensource -release -make libs -xplatform linux-aarch64-gnu-g++ -pch -qt-libjpeg -qt-libpng -qt-zlib -no-sse2 -no-openssl -no-cups -no-glib -no-dbus -xcb -no-separate-debug-info -opengl es2 -egl -eglfs -qpa xcb -linuxfb -recheck-all -skip webengine -nomake examples -nomake tests -shared -skip purchasing -skip quick3d -skip sensors -skip speech -skip datavis3d -skip andriodextras -skip gamepad
### 2.2 编译
配置成功后,运行以下命令编译代码(-j8表示使用8线程并行编译可根据需要或实际情况修改该数值
> sudo make -j8
### 2.3 安装
编译成功后运行以下命令打包安装Qt库打包安装后的库可直接压缩后在其它同样或类似环境中解压使用
> sudo make install
## 附录A常见编译错误
### 1. QBasicMutex::lockInternal(int)重定义
- 错误描述:
> qmutex_linux.cpp:multiple definition of 'QBasicMutex::lockInternal(int)',
- 解决问题:
> As in qmutex.cpp it directly" #include qmutex_linux.cpp", as a result the content of qmutex_linux.cpp will be part of qmutex.cpp.And in the thread.pro, the SOURCES +=qmutex.cpp qmutex_linux.cpp, then during link, the two file have same symbols will be detected.When I delete qmutex_linux.cpp from SOURCES, there is no problem any more.
[参考文章](https://blog.csdn.net/qq_43417144/article/details/130680388)

267
Qt码规范.md Normal file
View File

@ -0,0 +1,267 @@
# 开发团队C++编码规范
- [开发团队C++编码规范](#开发团队c编码规范)
- [代码风格](#代码风格)
- [缩进](#缩进)
- [变量声明](#变量声明)
- [空白](#空白)
- [大括号](#大括号)
- [圆括号](#圆括号)
- [Switch 语句](#switch-语句)
- [断行](#断行)
- [继承与关键字 `virtual`](#继承与关键字-virtual)
- [通用例外](#通用例外)
- [附录A 参考列表](#附录a-参考列表)
## 代码风格
### 缩进
- 采用4个空格
- 空格不要用TAB
### 变量声明
- 每行一个变量
- 尽可能避免短的变量名(比如"a", "rbarr", "nughdeget")
- 单字符的变量只在临时变量或循环的计数中使用
- 等到真正需要使用时再定义变量
```cpp
// 错误示例
int a, b;
char *c, *d;
// 正确
int height;
int width;
char *nameOfThis;
char *nameOfThat;
```
- 以小写字符开头,后续单词以大写开头
- 避免使用缩写
```cpp
// 错误示例
short Cntr;
char ITEM_DELIM = '';
// 正确
short counter;
char itemDelimiter = '';
```
- 类名总是以大写开头。公有类以Q开头(QRgb)公有函数通常以q开头(qRgb)。
### 空白
- 利用空行将语句恰当地分组
- 总是使用一个空行(不要空多行)
- 总是在每个关键字和大括号前使用一个空格
```cpp
// 错误示例
if(foo){
}
// 正确
if (foo) {
}
```
- 对指针和引用,在类型和*&之间加一个空格,但在*&与变量之间不加空格
```cpp
char *x;
const QString &myString;
const char* const y = "hello";
```
- 二元操作符前后加空白
- 类型转换后不加空白
- 尽量避免C风格的类型转换
```cpp
// 错误示例
char* blockOfMemory = (char* ) malloc(data.size());
// 正确
char *blockOfMemory = reinterpret_cast<char*>(malloc(data.size()));
```
### 大括号
- 基本原则:左大括号和语句保持在同一行:
```cpp
// 错误示例
if (codec)
{
}
// 正确
if (codec) {
}
```
- 例外:函数定义和类定义中,左大括号总是单独占一行:
```cpp
static void foo(int g)
{
qDebug("foo: %i", g);
}
class Moo
{
};
```
- 控制语句的body中只有一行时不使用大括号
```cpp
// 错误示例
if (address.isEmpty()) {
return false;
}
for (int i = 0; i < 10; +''i) {
qDebug("%i", i);
}
// 正确
if (address.isEmpty())
return false;
for (int i = 0; i < 10;i)
qDebug("%i", i);
```
- 例外1如果父语句跨多行则使用大括号
```cpp
// 正确
if (address.isEmpty() || !isValid()
|| !codec) {
return false;
}
```
- 例外2在if-else结构中有一处跨多行则使用大括号
```cpp
// 错误示例
if (address.isEmpty())
return false;
else {
qDebug("%s", qPrintable(address));
it;
}
// 正确
if (address.isEmpty()) {
return false;
} else {
qDebug("%s", qPrintable(address));
it;
}
// 错误示例
if (a)
if (b)
else
// 正确
if (a) {
if (b)
else
}
```
- 如果控制语句的body为空则使用大括号
```cpp
// 错误示例
while (a);
// 正确
while (a) {}
```
### 圆括号
- 使用圆括号将表达式分组
```cpp
// 错误示例
if (a && b || c)
// 正确
if ((a && b) || c)
// 错误示例
a | b & c
// 正确
(a + b) & c
```
### Switch 语句
- case 和 switch 位于同一列
- 每一个case必须有一个break(或renturn)语句或者用注释说明无需break
```cpp
switch (myEnum) {
case Value1:
doSomething();
break;
case Value2:
doSomethingElse();
// fall through
default:
defaultHandling();
break;
}
```
### 断行
- 保持每行短于100 个字符,需要时进行断行
- 逗号放一行的结束,操作符放到一行的开头。如果你的编辑器太窄,一个放在行尾的操作符不容易被看到。
```cpp
// 正确
if (longExpression
+ otherLongExpression
+ otherOtherLongExpression) {
}
// Wrong
if (longExpression +
otherLongExpression +
otherOtherLongExpression) {
}
```
### 继承与关键字 `virtual`
- 重新实现一个虚函数时,头文件中 不 放置 virtual 关键字。
### 通用例外
如果它使你的代码看起来不好,你可以打破任何一个规则 。
## 附录A 参考列表
1. [Qt编码风格/Qt Coding Style](https://wiki.qt.io/Qt_Coding_Style)
2. [LLVM编码标准/LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html)
3. [谷歌C++风格指南/Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
4. [C++核心指南/Cpp Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)

View File

@ -1,3 +1,7 @@
# wiki
企业知识库通过Markdown构建内部知识分享平台
企业知识库通过Markdown构建内部知识分享平台
- 创建企业开发团队代码规范
- 技术分享
- ...

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<map name = "ddmap" type="projected" version="2">
<options>
<terrain driver = "rex" lighting = "true" skirt_ratio="0.05" min_tile_range_factor = "6" first_lod = "0" blending = "false" color = "#ffffffff" tile_size = "17" normalize_edges = "true" compress_normal_maps = "false" normal_maps = "true" min_expiry_frames = "0" min_expiry_time = "0"/>
<!-- <profile>plate-carre</profile> -->
<profile>spherical-mercator</profile>
</options>
<image name="world" driver="tms" opacity = "1.0" format="png">
<url>E:/GISData/Imagery/tms.xml</url>
</image>
</map>

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 KiB

View File

@ -0,0 +1,174 @@
# osgEarth构建六边形网格兵棋地图示例
  在osgEarth中添加了osg::Geode绘制蜂窝状六边形网格效果包括墨卡托平面地图地理坐标平面地图三维地球等多种模式
![alt text](assets/osgEarth六边形网格/image.png)
```cpp
// 函数:创建六边形蜂窝网格线,三维地球
osg::ref_ptr<osg::Geometry> createHexagonWireframe(const osgEarth::GeoExtent& extent, float radius, int rows, int cols) {
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
auto fromSRS = osgEarth::SpatialReference::get("wgs84");
auto srs = extent.getSRS();
// 计算每个六边形中心点的地理坐标
float height = std::sqrt(3.0f) * radius;
float lonDelta = radius;// extent.width() / cols;
float latDelta = radius;// extent.height() / rows;
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
float lonDelta = col * 1.5f * radius;
float latDelta = row * height;
if (col % 2 == 1)
latDelta += height / 2.0f;
float lon = 108.0 + lonDelta;
float lat = 35.0 + latDelta;
osg::Vec3d centerGeo(lon, lat, 3000.0);
// 计算六边形的顶点
for (int i = 0; i < 6; ++i)
{
float angle = osg::PI * 2.0f * float(i) / 6.0f;
float x = radius * std::cos(angle);
float y = radius * std::sin(angle);
osg::Vec3d vertexXYZ;
osgEarth::GeoPoint pppp(fromSRS, osg::Vec3d(lon + x, lat + y, 1.0));
pppp.transformInPlace(srs);
pppp.toWorld(vertexXYZ);
//vertices->push_back(centerXYZ + vertexXYZ - centerGeo);
vertices->push_back(vertexXYZ);
}
}
}
geometry->setVertexArray(vertices);
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_LINES);
int numHexagons = rows * cols;
for (int i = 0; i < numHexagons; ++i) {
int offset = i * 6;
for (int j = 0; j < 6; ++j) {
indices->push_back(offset + j);
indices->push_back(offset + (j + 1) % 6);
}
}
geometry->addPrimitiveSet(indices);
// 启用 VBO
geometry->setUseVertexBufferObjects(true);
// 设置线宽
osg::ref_ptr<osg::StateSet> stateSet = geometry->getOrCreateStateSet();
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(1.0f); // 设置线宽为 1.0
stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return geometry;
}
// 函数:创建六边形蜂窝网格线,平面地图
osg::ref_ptr<osg::Geometry> createHexagonWireframe(double startX,double startY, float radius, int rows, int cols) {
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
// 计算每个六边形中心点的地理坐标
float height = std::sqrt(3.0f) * radius;
for (int row = 0; row < rows; ++row)
{
for (int col = 0; col < cols; ++col)
{
float xDelta = col * 1.5f * radius;
float yDelta = row * height;
if (col % 2 == 1)
yDelta += height / 2.0f;
float lon = startX + xDelta;
float lat = startY + yDelta;
// 计算六边形的顶点
for (int i = 0; i < 6; ++i)
{
float angle = osg::PI * 2.0f * float(i) / 6.0f;
float x = radius * std::cos(angle);
float y = radius * std::sin(angle);
//vertices->push_back(centerXYZ + vertexXYZ - centerGeo);
vertices->push_back(osg::Vec3d(lon + x, lat + y, 1.0));
}
}
}
geometry->setVertexArray(vertices);
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_LINES);
int numHexagons = rows * cols;
for (int i = 0; i < numHexagons; ++i) {
int offset = i * 6;
for (int j = 0; j < 6; ++j) {
indices->push_back(offset + j);
indices->push_back(offset + (j + 1) % 6);
}
}
geometry->addPrimitiveSet(indices);
// 启用 VBO
geometry->setUseVertexBufferObjects(true);
// 设置线宽
osg::ref_ptr<osg::StateSet> stateSet = geometry->getOrCreateStateSet();
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(1.0f); // 设置线宽为 1.0
stateSet->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return geometry;
}
int main(int argc, char* argv[])
{
auto ddMap = osgDB::readNodeFile("E:/GISData/Imagery/2dmap.earth");
auto mapNode = osgEarth::MapNode::findMapNode(ddMap);
osgEarth::GeoPoint start(osgEarth::SpatialReference::get("wgs84"), 108.0, 35.0);
start.transformInPlace(mapNode->getMapSRS());
auto hexagon222 = createHexagonWireframe(start.x(), start.y()
, 500, 100, 100);
hexagon222->getOrCreateStateSet()->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0.0, 1.0, false), osg::StateAttribute::ON);
osgEarth::GLUtils::setLighting(hexagon222->getOrCreateStateSet(), osg::StateAttribute::OFF);
mapNode->addChild(hexagon222);
auto m = new osgEarth::EarthManipulator;
osgViewer::Viewer viewer;
viewer.setSceneData(ddMap);
viewer.setCameraManipulator(m);
viewer.getCamera()->addCullCallback(new osgEarth::AutoClipPlaneCullCallback(mapNode));
viewer.realize();
m->setViewpoint(osgEarth::Viewpoint("", 108, 35, 0.0, 0.0, -89.9, 100000));
return viewer.run();
}
```
## 附件
![2dmap.earth](assets/osgEarth六边形网格/2dmap.earth)
## 性能问题
* 考虑使用instanced drawing
* 使用kd-tree
* ...

60
blog/资源分享.md Normal file
View File

@ -0,0 +1,60 @@
# 好用的资源分享
- [好用的资源分享](#好用的资源分享)
- [网站类](#网站类)
- [Qt](#qt)
- [工具软件](#工具软件)
- [开发人员工具](#开发人员工具)
- [逆向·破解](#逆向破解)
- [逆向工具](#逆向工具)
- [破解软件网站](#破解软件网站)
## 网站类
### Qt
- [Qt官网](https://www.qt.io/)
- [Qt下载站](https://download.qt.io/)
- [Qt官方论坛](https://forum.qt.io/)
- [Qt中文论坛](http://www.qtcn.org/)
- [Qt开发库二进制下载](https://build-qt.fsu0413.me/)
- [飞扬青云博客](https://blog.csdn.net/feiyangqingyun)
## 工具软件
- Everything 文件搜索
- PicPick 批量截屏及简单编辑
- Camtasia 视频剪辑
- OBS Studio 开源屏幕录制软件
- FormatFactory 格式工厂
- PowerToys 微软官方出品的常用操作集合,官方出品,必属精品!
- MasterPDFEditor PDF编辑工具合并、分割...
- MindManager思维导图工具
- 向日葵 远程桌面工具
- SQLiteManager SQLite数据库管理工具
- 太乐地图下载工具 卫星影像下载软件
- ScreenToGif 屏幕录像为GIF动画
- 文件时间修改
- 批量文本文件转UTF-8 BOM
## 开发人员工具
- Visual Assist X
## 逆向·破解
### 逆向工具
- x64Dbg
- Die
- ResourceHacker 修改exe图标等程序资源
### 破解软件网站
- [吾爱破解](https://www.52pojie.cn/)
- [飘云阁](http://www.chinapyg.com/)

1465
llvm-coding-standards.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
# vcpkg安装库失败常见错误及其解决方法
## 目录
- [vcpkg安装库失败常见错误及其解决方法](#vcpkg安装库失败常见错误及其解决方法)
- [目录](#目录)
- [1. 科学上网](#1-科学上网)
- [1.1 控制台设置代理](#11-控制台设置代理)
- [1.2 vcpkg包下载失败](#12-vcpkg包下载失败)
- [1.3 osg/osgEarth网络代理环境变量](#13-osgosgearth网络代理环境变量)
- [2. 遇到某些库编译错误时,在本地修改代码并使用修改后的代码编译](#2-遇到某些库编译错误时在本地修改代码并使用修改后的代码编译)
- [3. vcpkg ports内可以修改库的配置如工程目录windows SDK版本以及部分错](#3-vcpkg-ports内可以修改库的配置如工程目录windows-sdk版本以及部分错)
- [4. 找不到Windows SDK库的错误修改https://github.com/microsoft/vcpkg/issues/8288](#4-找不到windows-sdk库的错误修改httpsgithubcommicrosoftvcpkgissues8288)
- [5. vc错误: `error MSB4115: 函数“exists”只接受标量值但其参数“$(ForceImportBeforeCppTargets)”的计算结果为`](#5-vc错误-error-msb4115-函数exists只接受标量值但其参数forceimportbeforecpptargets的计算结果为)
- [5. 编译GDAL 出现 +{}; 加号不明确](#5-编译gdal-出现--加号不明确)
- [6. Windows 7 Python 3.8](#6-windows-7-python-38)
## 1. 科学上网
vcpkg中大部份依赖均托管在github仓库中由于国内特殊的网络环境导致github大部分时间无法正常访问尤其是下载较大源码包或文件时会出现网络错误此时需要通过科学上网措施目前统一使用Mielink建立代理上网建立代理后一般会有一个本地代理端口如果配置的不是全局代理那么有时需要在控制台设定上网代理下面介绍代理配置方法及一些网络相关的其它错误...
### 1.1 控制台设置代理
控制台设置网络代理需要将2801修改成本机的科学上网代理端口
* set HTTP_PROXY=http://127.0.0.1:2801
* set HTTPS_PROXY=http://127.0.0.1:2801
### 1.2 vcpkg包下载失败
* 有时使用vcpkg安装指定库时由于网络抽风有时会出现无法成功下载某些源码包的情况此时可先使用vcpkg安装一次确认源码包的下载目录及保存的文件名此二者有时不一致然后使用以下方法下载压缩包重命名后放在vcpkg的download目录中即可
* 关于库下载错误可以通过迅雷或其它工具下载然后添加到download目录注意从命令行确认保存的文件名
### 1.3 osg/osgEarth网络代理环境变量
* set OSGEARTH_HTTP_DEBUG=1
* set OSG_CURL_PROXY="127.0.0.1"
* set OSG_CURL_PROXYPORT=2801
## 2. 遇到某些库编译错误时,在本地修改代码并使用修改后的代码编译
正常使用vcpkg install xxxx安装库时出现编译错误通过编译日志可以定位到具体的编译错误但是默认情况下每次install时都会从压缩包中重新解压一份新的代码到本地临时目录因此无法对源代码进行修改并使用修复后的代码进行编译安装此时只需要在install时额外指定--editable选项即可使本次编译不生成临时源码目录在一个固定的源码目录中然后可手工编辑修改此目录中源代码然后再使用install此时仍需指定--editable选项安装这时就会使用修改后的代码进行编译了...
通过prompt启动然后进入vcpkg目录
VCPKG install 库名 --editable可以在编译前修改库源码
## 3. vcpkg ports内可以修改库的配置如工程目录windows SDK版本以及部分错
## 4. 找不到Windows SDK库的错误修改https://github.com/microsoft/vcpkg/issues/8288
## 5. vc错误: `error MSB4115: 函数“exists”只接受标量值但其参数“$(ForceImportBeforeCppTargets)”的计算结果为`
* 报错信息:
> 1>节点 1 上的项目“xxxxxx\buildtrees\libpq\x64-windows-dbg\libpq.vcxproj”(默认目标)。
> 1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.Cpp.Current.targets(14,11): error MSB4115: 函数“exists”只接受标量值但其参数“$(ForceImportBeforeCppTargets)”的计算结果为“C:/Users/gz/Desktop/vcpkg-2023.08.09/scripts/buildsystems/msbuild/vcpkg.targets;C:/Users/gz/Desktop/vcpkg-2023.08.09/buildtrees/libpq/x64-windows-dbg/vcpkg-libs.props”不是标量值。 [xxxxxx\buildtrees\libpq\x64-windows-dbg\libpq.vcxproj]
> 1>已完成生成项目“xxxxxx\buildtrees\libpq\x64-windows-dbg\libpq.vcxproj”(默认目标)的操作 - 失败。
* 参考链接https://github.com/conan-io/conan/issues/7806
* 解决方案:
> 修改对应库ports目录内的msvc.cmake文件
> /p:ForceImportBeforeCppTargets=\"${SCRIPTS}/buildsystems/msbuild/vcpkg.targets\"
>
> /p:ForceImportBeforeCppTargets=\"${build_path}/vcpkg-libs.props\"
## 5. 编译GDAL 出现 +[](){}; 加号不明确
* 错误信息:
> xxxxxx\buildtrees\gdal\src\v3.7.1-30395dad39\ogr\ogrsf_frmts\openfilegdb\filegdbindex_write.cpp(1298): error C2593: “operator +”不明确
> xxxxxx\buildtrees\gdal\src\v3.7.1-30395dad39\ogr\ogrsf_frmts\openfilegdb\filegdbindex_write.cpp(1298): note: 可能是“内置 C++ operator+(void (__cdecl *)(std::vector<GByte,std::allocator<_Ty>> &,const __int64 &,int))”
> with
> [
> _Ty=GByte
> ]
> xxxxxx\buildtrees\gdal\src\v3.7.1-30395dad39\ogr\ogrsf_frmts\openfilegdb\filegdbindex_write.cpp(1298): note: 或 “内置 C++ operator+(void (__vectorcall *)(std::vector<GByte,std::allocator<_Ty>> &,const __int64 &,int))”
> with
> [
> _Ty=GByte
> ]
> xxxxxx\buildtrees\gdal\src\v3.7.1-30395dad39\ogr\ogrsf_frmts\openfilegdb\filegdbindex_write.cpp(1298): note: 尝试匹配参数列表“(OpenFileGDB::FileGDBTable::CreateSpatialIndex::<lambda_0019e43095a67889bd1988df31ec838d>)”时
* 原因分析由于C++版本原因,低版本并不支持该转换,因此直接去掉转换即可
* 解决方法尝试去掉lambda前面的加号(该加号用于将lambda表达式转为传统函数指针兼容老代码
## 6. Windows 7 Python 3.8
如果用到的库依赖了Python3.8以上的版本是无法在windows7正常运行的解决办法是用3.8狸猫换太子无痛替换掉vcpkg自动下载的python
貌似打补丁也可以实现让windows7支持3.9.2运行

View File

@ -1,5 +1,15 @@
# 办公室文件共享
- [办公室文件共享](#办公室文件共享)
- [简介](#简介)
- [1. 文件存储服务介绍](#1-文件存储服务介绍)
- [2. 使用流程](#2-使用流程)
- [2.1 内网使用(优先使用)](#21-内网使用优先使用)
- [2.1.1 账户初始化](#211-账户初始化)
- [2.1.2 连接共享目录](#212-连接共享目录)
- [2.2 外网环境使用](#22-外网环境使用)
## 简介
  办公室近日引入了共享存储服务,这项举措旨在提升团队间的协作效率和数据管理的便捷性及安全性。通过共享存储服务,团队成员可以将文件、文档、图片等资料集中存储在一个统一的平台上,而无需依赖传统的文件共享方式,如电子邮件附件或移动存储设备。这意味着团队成员可以随时随地访问所需的文件,无论是在办公室、外出办事的途中,甚至在家里。此外,共享存储服务还提供了权限管理功能,团队管理员可以灵活地控制不同成员对文件的访问权限,确保机密性和安全性。总的来说,共享存储服务的引入将大大简化团队间的文件共享和管理流程,为团队协作提供了更高效、更便捷的工具和平台。
---
@ -13,18 +23,42 @@
---
## 2. 使用流程
### 2.1 账户初始化
### 2.1 内网使用(优先使用)
  在办公室办公时优先使用内网方式此时文件访问和传输不需要经过公网服务器带宽不受限制速度可达50-100MB/s具体数据取决于传输的文件。
#### 2.1.1 账户初始化
  系统默认为团队成员创建了以自己姓名命名的账户,首次使用需要通过该链接:[密码重置链接](http://192.168.1.11:9888/) 设置用户密码使用(每个用户可设置一次密码),如忘记密码,可联系管理员重置。
![账户初始化](assets/办公室文件共享/image-1.png)
### 2.2 连接共享目录
[![账户初始化](assets/办公室文件共享/image-1.png)](http://192.168.1.11:9888/)
#### 2.1.2 连接共享目录
![操作流程图](assets/办公室文件共享/image.png)
1. 打开计算机文件管理器
2. 在【此电脑】右键
3. 在弹出的菜单中,点击【映射网络驱动器】
4. 在弹出的界面中,【文件夹】输入框输入 **\\192.168.1.11\Shared**
4. 在弹出的界面中,【文件夹】输入框输入 **\\\\192.168.1.11\\Shared**
5. 勾选输入框下面的【登陆时重新连接】和【使用其他凭据连接】
6. 点击【完成】按钮
7. 在弹出的界面中输入用户名和密码,并勾选【记住我的凭据】
8. 点击【确定】按钮
9. 如无误,则在计算机界面中会成功添加一个新的网络磁盘。
![网络驱动器](assets/办公室文件共享/image-2.png)
![网络驱动器](assets/办公室文件共享/image-2.png)
### 2.2 外网环境使用
  当不在办公室时临时需要访问共享目录的资料此时无法通过内网地址直接访问服务器需要通过公网文件管理页面访问共享目录可在网页中完成文件的查看、预览、编辑、删除、上传、下载等操作需要注意的是此种访问方式受公司租用的公网服务器带宽限制目前为3Mbps因此如果通过该种方式上传和下载文件时速度会比较慢因此应尽量避免使用该种方式操作大文件。
访问地址为:[http://pan.vuegic.com/](http://pan.vuegic.com/)
[![公网访问页面预览图](assets/办公室文件共享/image-3.png)](http://pan.vuegic.com/)
注:用户名和密码与内网访问时一致,如无法访问,请联系管理员开通账号。
登录成功后,可查看共享目录的文件,并对其进行操作:
![alt text](assets/办公室文件共享/image-4.png)

669
编码规范.md Normal file
View File

@ -0,0 +1,669 @@
# 开发团队C++编码规范
- [开发团队C++编码规范](#开发团队c编码规范)
- [代码风格](#代码风格)
- [缩进](#缩进)
- [变量声明](#变量声明)
- [空白](#空白)
- [大括号](#大括号)
- [圆括号](#圆括号)
- [Switch 语句](#switch-语句)
- [断行](#断行)
- [继承与关键字 `virtual`|`override`](#继承与关键字-virtualoverride)
- [include 规范](#include-规范)
- [使用class和struct关键字](#使用class和struct关键字)
- [使用auto类型推导提高代码可读性](#使用auto类型推导提高代码可读性)
- [小心auto带来的不必要拷贝](#小心auto带来的不必要拷贝)
- [头文件独立](#头文件独立)
- [库层次](#库层次)
- [尽可能的减少 #include](#尽可能的减少-include)
- [保持私有的内部头文件](#保持私有的内部头文件)
- [使用 namespace 限定符莱实现前置声明的函数](#使用-namespace-限定符莱实现前置声明的函数)
- [提前退出或 continue 以简化代码](#提前退出或-continue-以简化代码)
- [return 之后不要使用 else](#return-之后不要使用-else)
- [将判断循环转换为判断函数](#将判断循环转换为判断函数)
- [通用例外](#通用例外)
- [附录A 参考列表](#附录a-参考列表)
## 代码风格
### 缩进
- 采用4个空格进行缩进
- 使用空格不要用TAB
### 变量声明
- 每行一个变量
```cpp
// 错误示例
int width, height;
// 正确
int height;
int width;
```
- 尽可能避免短的无意义的变量名(比如"a", "rbarr", "nughdeget")
```cpp
// 错误示例
int a;
double b;
// 正确
int number;
double speed;
```
- 单字符的变量只在临时变量或循环的计数中使用
```cpp
// 错误示例
int i = 1025;
// 正确
int count = 1025;
for ( auto i = 0; i < count; ++i )
{
...
}
```
- 等到真正需要使用时再定义变量
```cpp
// 错误示例
void exampleFunction()
{
int step = 0; // 变量定义在函数开头,但尚未使用
int number = 0; // 变量定义在函数开头,但尚未使用
// 此处是其它业务逻辑代码
...
// 很久之后才使用 变量 x 和 y
step = 5;
number = 10;
}
// 正确
void exampleFunction()
{
// 变量在需要时定义
int step = 5;
int number = 10;
std::cout << "step: " << step << ", number: " << number << "\n";
}
```
- 首字母小写,后续单词以大写开头(驼峰式)
- 避免使用缩写
```cpp
// 错误示例
short Cntr;
char ITEM_DELIM = '';
// 正确
short counter;
char itemDelimiter = '';
```
- 类名总是以大写开头
```cpp
// 错误示例
class person
{
...
}
// 正确
class Person
{
...
}
```
### 空白
- 利用空行将语句恰当地分组
- 总是使用一个空行(不要空多行)
- 总是在每个关键字和大括号前使用一个空格
```cpp
// 错误示例
if(foo)
{
}
// 正确
if (foo)
{
}
```
- 对指针和引用,在类型和*、&之间加一个空格,但在*、&与变量之间不加空格?
```cpp
char *something;
const QString &myString;
const char* const message = "hello";
```
- 二元操作符前后加空白
- 类型转换后不加空白
- 尽量避免C风格的类型转换
```cpp
// 错误示例
char* blockOfMemory = (char* ) malloc(data.size());
// 正确
char *blockOfMemory = reinterpret_cast<char*>(malloc(data.size()));
```
### 大括号
- 基本原则:左大括号和语句之间换行,左大括号总是单独占一行
```cpp
// 错误示例
if (codec){
}
// 正确
if (codec)
{
}
```
- 例外1定义命名空间时左大括号与命名空间同行
```cpp
namespace Test {
qDebug("foo: %i", g);
}
```
- 例外2控制语句的body为空时大括号与控制语句同行
```cpp
while(a) {}
```
- 控制语句的body中只有一行时不使用大括号
```cpp
// 错误示例
if (address.isEmpty())
{
return false;
}
for (int i = 0; i < 10; +''i)
{
qDebug("%i", i);
}
// 正确
if (address.isEmpty())
return false;
for (int i = 0; i < 10;i)
qDebug("%i", i);
```
- 例外1如果父语句跨多行则使用大括号
```cpp
// 正确
if (address.isEmpty() || !isValid()
|| !codec)
{
return false;
}
```
- 例外2在if-else结构中有一处跨多行则使用大括号
```cpp
// 错误示例
if (address.isEmpty())
return false;
else
{
qDebug("%s", qPrintable(address));
it;
}
// 正确
if (address.isEmpty())
{
return false;
}
else
{
qDebug("%s", qPrintable(address));
it;
}
// 错误示例
if (a)
if (b)
else
// 正确
if (a)
{
if (b)
else
}
```
- 如果控制语句的body为空则使用大括号
```cpp
// 错误示例
while (a);
// 正确
while (a) {}
```
### 圆括号
- 使用圆括号将表达式分组,避免需要考虑运算符优先级的情况
```cpp
// 错误示例
if (a && b || c)
// 正确
if ((a && b) || c)
// 错误示例
a | b & c
// 正确
(a + b) & c
```
### Switch 语句
- case 和 switch 位于同一列
- 每一个case必须有一个break(或renturn)语句或者用注释说明无需break
```cpp
switch (myEnum)
{
case Value1:
doSomething();
break;
case Value2:
doSomethingElse();
// fall through
default:
defaultHandling();
break;
}
```
### 断行
- 保持每行短于100个字符需要时进行断行
- 逗号放一行的结束,操作符放到一行的开头。如果你的编辑器太窄,一个放在行尾的操作符不容易被看到。
```cpp
// 错误示例
if (longExpression +
otherLongExpression +
otherOtherLongExpression)
{
...
}
// 正确
if (longExpression
+ otherLongExpression
+ otherOtherLongExpression)
{
...
}
```
### 继承与关键字 `virtual`|`override`
- 子类中重新实现一个虚函数时,头文件中不放置 virtual 关键字但必须显式的标注override关键字。
### include 规范
在文件首部注释(和包含保护,如果是头文件)之后,该文件需要的最小 `#include` 列表应该被列出来。要求的 `#include` 顺序如下:
- 主模块头文件
- 局部的/私有的头文件
- 项目/子项目头文件 clang/..., lldb/..., llvm/..., etc
- 系统文件
并且每一个种类的头文件完整路径应该做一个排序。
主模块头文件适用于声明实现接口的 `.cpp` 文件的 `.h` 文件。该 `#include` 不管处在什么文件系统下总是应该第一个被包含。通过在实现该接口的第一包含头文件可以确保头文件没有隐藏需要但没有显式包含的依赖。同样的,这也是在 `.cpp`中一种指明接口声明在何处的记录。
项目和子项目的头文件应该从最高优先级到最低优先级分组理由同上。举个例子LLDB 同时依赖 clang 和 LLVM并且 clang 依赖 LLVM。所以一个 LLDB 源文件应该最先包含 LLDB ,其次是 clang 头文件,其次是 LLVM 头文件这样做是为了在源文件中的头文件或更前的头文件包含情况下降低LLDB头文件包含缺失的可能。clang 同样的应该在包含LLVM文件之前包含其自身的头文件。
### 使用class和struct关键字
在C++中,`class` 和 `struct` 关键字在绝大数的情况下可以互换。仅仅的区别在于定义一个 class 时所有的成员默认为 private而struct默认为 public。
- 给定 `class` 和 `struct` 的所有生命和定义必须使用同一个关键字
```cpp
// Avoid if `Example` is defined as a struct.
class Example;
// OK.
struct Example;
struct Example { ... };
```
- 当所有的成员都为公开声明时使用 `struct`
```cpp
// Avoid using `struct` here, use `class` instead.
struct Foo {
private:
int Data;
public:
Foo() : Data(0) { }
int getData() const { return Data; }
void setData(int D) { Data = D; }
};
// OK to use `struct`: all members are public.
struct Bar {
int Data;
Bar() : Data(0) { }
};
```
### 使用auto类型推导提高代码可读性
一些人主张在C++11种几乎总是使用auto的原则然而LLVM保持更温和的态度。仅在如果使用auto可以提升代码的可读性或者更利于维护的情况下使用。并不几乎总是使用 `auto`,而是在初始化像 `cast<Foo>(...)` 或者类型可以明显的从上下文中获取的地方中使用。其它时候 `auto` 良好用于其用途是无论如何该类型都会被抽象化,经常出现在容器的 `typedef` 之后如 `std::vector<T>::iterator`。
同样的C++14 新增类型可以为auto的通用lambda表达式可以在原本使用模板的地方使用它。
### 小心auto带来的不必要拷贝
`auto` 的便利性更容易遗忘它默认是拷贝的行为,尤其是在基于范围的循环,粗心的代价很昂贵。
值使用 `auto &` 指针使用 `auto *` 除非你需要进行拷贝。
```cpp
// Typically there's no reason to copy.
for (const auto &Val : Container) { observe(Val); }
for (auto &Val : Container) { Val.change(); }
// Remove the reference if you really want a new copy.
for (auto Val : Container) { Val.change(); saveSomewhere(Val); }
// Copy pointers, but make it clear that they're pointers.
for (const auto *Ptr : Container) { observe(*Ptr); }
for (auto *Ptr : Container) { Ptr->change(); }
```
### 头文件独立
头文件应该保持独立(独立编译)并且以`.h`结尾。非头文件的包含应该以`.inc`结尾并且谨慎使用。
所有的头文件都应该是独立的。用户或者重构工具不应该强制附加特定条件才能够包含这个头文件。特别的,一个头文件应该存在头文件保护和所有需要的其他头文件。
有一些及少见的情况,设计被包含的文件不是独立的。它们往往有意的被包含在不常用的地方,比如一个文件的中间位置。它们可能不使用头文件保护并且可能不包括必要的先决条件。这些文件的名称以 `.inc` 扩展。谨慎使用这种文件,尽可能使用独立的头文件。
通常而言,一个头文件应该被一个或多个 `.cpp` 实现。每一个 `.cpp` 文件都应该首先包含定义接口的头文件。确保头文件所有的依赖都能够显式正确的添加至该头文件中。
### 库层次
头文件目录(如 include/llvm/Foo定义了库Foo。库之间的依赖在它们实现lib/Foo中的 LLVMBuild.txt 定义。一个库应该仅使用依赖所列出库的内容。
一些经典的Unix链接器Mac & Windows 链接器比如lld不强制执行可以强制执行某些约束。Unix 链接器从左往右在命令行中搜索特定的库并且不会重复访问同一个库。这种情况下,库之间就不存在循环依赖关系。
这样不会完全强制的执行所有的相互库依赖,且重要的是不会执行由内联函数带来的头文件循环依赖。回答是否正确分层的一个好方法是判断 Unix 链接器是否可以正确链接使用非内联函数代替内联函数的程序。(对于所有依赖的有效顺序 - 由于链接的方案是线性的因此可能潜伏一些隐式的依赖A 依赖于B和C所以有效的顺序为“CBA” 或者“BCA”两种显示的依赖都在使用之前出现。但对于第一种情况B如果隐式的依赖于C仍然可以链接成功或者在第二种情况相反的依赖也可以链接成功
### 尽可能的减少 #include
`#include` 降低了编译的性能,在不是必需的时候不要包含,尤其是在头文件中。
有一些情况是你需要获取到类的定义再去使用或者继承它,这些情况则在文件的首部进行 `#include`。然而也要想到,存在非常多的情况是不需要拥有类的完整定义的。如果正在使用类指针或引用,则不必包含该头文件。如果只是的从原型函数或者方法中返回一个类的实例,也不需要头文件。实际上,在大多数的情况下,你根本不需要类的定义。不进行 `#include` 可以加速编译。
这个建议很容易导致偏激的态度,然而,你**必须**包含所有正在使用的头文件,无论是直接还是间接从其它文件包含。为确保你不会意外的忘记在你的模块头文件中包含头文件,确认在实现文件中**第一个**包含你的模块头文件(就像上面提到的)。这样,你后面就会发现不会再有隐藏的依赖了。
### 保持私有的内部头文件
很多模块实现非常复杂导致使用了多个实现文件(`.cpp`文件)。不要尝试将公共交互接口(帮助类,扩展函数等)放入到公共的模块头文件中。
如果你真的需要这么做的话,在相同的目录下放入一个私有的头文件让源文件局部包含。这样确保你的私有接口保留了私有属性并且不向外发布。
> 允许将扩展实现的方法放入到一个公共类自身中,但是需要让它们设为私有(保护),一切就正常。
### 使用 namespace 限定符莱实现前置声明的函数
当源文件中提供一个非内联(或者叫外部实现)的函数实现时,不要在源文件中打开 namespace 块namespace xx {})。相反的,使用 namespace 标记符来帮助确保你的定义匹配上已经存在的声明。像这样:
```cpp
// Foo.h
namespace llvm {
int foo(const char *s);
}
// Foo.cpp
#include "Foo.h"
using namespace llvm;
int llvm::foo(const char *s) {
// ...
}
```
这样做能够避免实现不能匹配头文件中声明的bug。举个例子下面的C++代码定义了一个新的重载`llvm::foo`来取代在头文件中存在函数声明的实现:
```cpp
// Foo.cpp
#include "Foo.h"
namespace llvm {
int foo(char *s) { // Mismatch between "const char *" and "char *"
}
} // end namespace llvm
```
这个错误在快构建完成之前不能够被捕获直到产生函数调用找不到函数定义的链接错误。如果这个函数使用namespace标记符来代替这个错误直接在这个定义编译时被捕获。
类方法实现必须类已经被命名并且新的重载不能够引入到外部,所以这个建议对它们不起作用。
### 提前退出或 continue 以简化代码
在阅读代码时,读者需要在记住有多少状态及前置条件去阅读代码块。为了减少尽可能缩进而又不是代码变得更难理解,在长循环中使用提前退出或者`continue`关键字是一个好的方法。观察未使用提前退出的代码:
```cpp
Value *doSomething(Instruction *I) {
if (!I->isTerminator() &&
I->hasOneUse() && doOtherThing(I)) {
... some long code ....
}
return 0;
}
```
这份代码当`if`作用体非常庞大时有一些问题。当你正在查看这个函数的顶部时对于是只做和结束指令相关的事情还是其他的判断操作是不够清晰的。其二由于if语句使注释难以布局相对的也更难以去描述这个判断为何很重要。其三当你深入代码时它已经被缩进了一级。最后当阅读函数的顶部代码时if判断的结构是不是为真的结果不够清晰你必须要阅读到函数的底端才知道返回了 null。
更好的代码格式如下:
```cpp
Value *doSomething(Instruction *I) {
// Terminators never need 'something' done to them because ...
if (I->isTerminator())
return 0;
// We conservatively avoid transforming instructions with multiple uses
// because goats like cheese.
if (!I->hasOneUse())
return 0;
// This is really just here for example.
if (!doOtherThing(I))
return 0;
... some long code ....
}
```
这修复了上面提到的那些问题。一个类似的问题频繁的出现在`for`循环中,一个简单的例子如下:
```cpp
for (Instruction &I : BB) {
if (auto *BO = dyn_cast<BinaryOperator>(&I)) {
Value *LHS = BO->getOperand(0);
Value *RHS = BO->getOperand(1);
if (LHS != RHS) {
...
}
}
}
```
当你的循环非常非常简短的循环时这种结构是良好的。但是当循环超过10-15行时用户在扫视时会变得难以阅读和理解。这种代码存在的问题是缩进的非常的快这意味着读者脑袋必须要保持大量的上下文来记住在这个循环中随即发生的事情因为他们不知道`if`条件是否或者何时存在 `else`。更强烈推荐的循环结构如下:
```cpp
for (Instruction &I : BB) {
auto *BO = dyn_cast<BinaryOperator>(&I);
if (!BO) continue;
Value *LHS = BO->getOperand(0);
Value *RHS = BO->getOperand(1);
if (LHS == RHS) continue;
...
}
```
在函数中使用尽快退出的好处是:减少循环的缩进,更易于描述为何条件为真,而没有 `else` 出现则在读者的脑袋中变得更加明显。如果一个循环非常的庞大,这些做法具有巨大的理解优势。
### return 之后不要使用 else
同样的理由如上(减少缩进和易于理解),请不要使用 `else`或者`else if`在终止的控制流之后,就像是 `return`, `break`, `continue`, `goto` 等等,如:
```cpp
case 'J': {
if (Signed) {
Type = Context.getsigjmp_bufType();
if (Type.isNull()) {
Error = ASTContext::GE_Missing_sigjmp_buf;
return QualType();
} else {
break; // Unnecessary.
}
} else {
Type = Context.getjmp_bufType();
if (Type.isNull()) {
Error = ASTContext::GE_Missing_jmp_buf;
return QualType();
} else {
break; // Unnecessary.
}
}
}
```
更好的做法如下:
```cpp
case 'J':
if (Signed) {
Type = Context.getsigjmp_bufType();
if (Type.isNull()) {
Error = ASTContext::GE_Missing_sigjmp_buf;
return QualType();
}
} else {
Type = Context.getjmp_bufType();
if (Type.isNull()) {
Error = ASTContext::GE_Missing_jmp_buf;
return QualType();
}
}
break;
```
这个例子更好的写法如下:
```cpp
case 'J':
if (Signed)
Type = Context.getsigjmp_bufType();
else
Type = Context.getjmp_bufType();
if (Type.isNull()) {
Error = Signed ? ASTContext::GE_Missing_sigjmp_buf :
ASTContext::GE_Missing_jmp_buf;
return QualType();
}
break;
```
这样做的目的是减少缩进和在阅读代码时需要跟踪的代码量。
### 将判断循环转换为判断函数
通过短循环计算一个 boolean 值是非常常见的写法。有一系列的常见方式,比如这种:
```cpp
bool FoundFoo = false;
for (unsigned I = 0, E = BarList.size(); I != E; ++I)
if (BarList[I]->isFoo()) {
FoundFoo = true;
break;
}
if (FoundFoo) {
...
}
```
相对这种循环的方式,我们更偏向使用一个使用尽早退出的判断函数(可能是静态):
```cpp
/// \returns true if the specified list has an element that is a foo.
static bool containsFoo(const std::vector<Bar*> &List) {
for (unsigned I = 0, E = List.size(); I != E; ++I)
if (List[I]->isFoo())
return true;
return false;
}
...
if (containsFoo(BarList)) {
...
}
```
这样做有很多理由减少了缩进并且分离出可以让其它代码检测相同判断的共享代码。更重要的是让你强制为这个函数起一个名字并且强制让你再为它写上注释。在这个简短的例子中没有添加很多值然而如果这个if条件非常复杂读者通过这个判断可以非常容易地理解代码。而不是一开始就面对如何检测 `BarList` 中是否包含了 `foo` 的内联细节,我们可以信任这个函数名称并且继续在更好的位置进行阅读。
### 通用例外
如果它使你的代码看起来不好,你可以打破任何一个规则 。
## 附录A 参考列表
1. [Qt编码风格/Qt Coding Style](https://wiki.qt.io/Qt_Coding_Style)
2. [LLVM编码标准/LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html)
3. [谷歌C++风格指南/Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
4. [C++核心指南/Cpp Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)