面向亿行 C/C++ 代码的静态分析系统设计及实践-肖枭静态分析+代码评审的实践 学习和强调,红线和惩罚,100%的测试 覆盖率,和事后复盘并不够 有经验的程序员也会犯错 对代码提要求很难监督落实 测试更多是验证功能,很难检测编码缺陷 代码的快速变化使质量更难管 生产质量是责任 靠运维和事后复盘善后够吗? 静态分析工具:半智能的代码分析机器人 静态分析辅助代码评审 自动化工具+流程才是未来 Bug! Thx! Bug! “这是以前的业务逻辑,不用修” “这别人写的代码,不关我事” 大量报告引起不适 刚写的代码立即自动扫描,程序员强迫使用 只体现新增代码问题,责任边界清晰 评审流程多人督促 渐进式开启更多检查器 增量分析减少不适 • 软件工程师一天被邀请进行多次 代码评审,这些都不是他们自身 的KPI • 一旦工期紧996,人工评审容易 变成走形式 • 任务挂着还容易造成工程师焦虑 降低工程师劳动强度 用基线数据训练模型 用聚类和离群检测找到违反者 红黑榜鼓励参与者 降低感知误报率 用数据风控的方式管理 总结:代码评审中的静态分析 无需额外操作,不改变程序员习惯的流程 只分析变化的代码引起的问题 使用频次高,可形成数据驱动的分析器改进和 代码质量监控 推动规范落地和培训教育新员工 提高人工评审效果 零培训成本强制使用 基于gitlab的自动代码评审演示0 码力 | 39 页 | 6.88 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针16 位或者说 2 字节。 int 是整数类型,大小为 32 位或者说 4 字节。 long long 是超长整数类型,大小为 64 位或者说 8 字节。 long 比较特殊,在 Unix 上随系统位数变化, Windows 上始终是 32 位。 C 语言的基础整数类型 类型 Unix 32 位 Unix 64 位 Windows 32 位 Windows 64 位 char 8 位 8 位 8 址值存在整型变量里。 • 而 32 位平台上的指针是 32 位, 64 位平台上的指针是 64 位。 • 所以是不是需要根据当前平台来判断要使用哪一种代码了? • 不需要,可以用自动随系统位数变化的 intptr_t 和 uintptr_t ! • intptr_t 在 32 位平台上等价于 int32_t ;在 64 位平台上等价于 int64_t • uintptr_t 在 32 位平台上等价于 sizeof(intptr_t) = sizeof(void *) = sizeof(uintptr_t) size_t :表示大小的整数类型,其实等价于 uintptr_t • 除了指针需要随系统位数变化之外,数组的长度也是需要随系统位数变化的。 • 如果 64 位系统上 size_t 还是 uint32_t ,那就无法表示超过 4GB 大小的数组了。 • 今日乳 ja 笑话: java 的字符串常量不能超过 655350 码力 | 128 页 | 2.95 MB | 1 年前3
Hello 算法 1.1.0 C++ 版时间比算法 B 短;但在另一台配置不同的计算机中,可能得到相反的测试结果。这意味着我们需要在各种机 器上进行测试,统计平均效率,而这是不现实的。 另一方面,展开完整测试非常耗费资源。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入 数据量较小时,算法 A 的运行时间比算法 B 短;而在输入数据量较大时,测试结果可能恰恰相反。因此,为 了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。 < 阶乘阶 第 2 章 复杂度分析 hello‑algo.com 33 图 2‑9 常见的时间复杂度类型 1. 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 在以下函数中,尽管操作数量 size 可能很大,但由于其与输入数据大小 ? 无关,因此时间复杂度仍为 ?(1) : // === File: time_complexity.cpp === 基于链表可实现:栈、队列、哈希表、树、堆、图等。 链表在初始化后,仍可以在程序运行过程中对其长度进行调整,因此也称“动态数据结构”。数组在初始化后 长度不可变,因此也称“静态数据结构”。值得注意的是,数组可通过重新分配内存实现长度变化,从而具备 一定的“动态性”。 Tip 如果你感觉物理结构理解起来有困难,建议先阅读下一章,然后再回顾本节内容。 3.2 基本数据类型 当谈及计算机中的数据时,我们会想到文本、图片、视频、语音、3D0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版现就会更好。也 就是说,算法在不同的机器上的测试结果可能是不一致的。这意味着我们需要在各种机器上进行测试,统计 平均效率,而这是不现实的。 另一方面,展开完整测试非常耗费资源。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入 数据量较小时,算法 A 的运行时间比算法 B 短;而在输入数据量较大时,测试结果可能恰恰相反。因此,为 了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。 阶乘阶 第 2 章 复杂度分析 www.hello‑algo.com 33 图 2‑9 常见的时间复杂度类型 1. 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 在以下函数中,尽管操作数量 size 可能很大,但由于其与输入数据大小 ? 无关,因此时间复杂度仍为 ?(1) : // === File: time_complexity.cpp === 基于链表可实现:栈、队列、哈希表、树、堆、图等。 链表在初始化后,仍可以在程序运行过程中对其长度进行调整,因此也称“动态数据结构”。数组在初始化后 长度不可变,因此也称“静态数据结构”。值得注意的是,数组可通过重新分配内存实现长度变化,从而具备 一定的“动态性”。 Tip 如果你感觉物理结构理解起来有困难,建议先阅读下一章,然后再回顾本节内容。 3.2 基本数据类型 当谈及计算机中的数据时,我们会想到文本、图片、视频、语音、3D0 码力 | 379 页 | 18.48 MB | 10 月前3
Hello 算法 1.0.0b5 C++版运行时间比算法 B 短;但在另一台配置不同的计算机中,我们可能得到相反的测试结果。这意味着我们需要 在各种机器上进行测试,统计平均效率,而这是不现实的。 另一方面,展开完整测试非常耗费资源。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入 数据量较小时,算法 A 的运行时间比算法 B 更少;而输入数据量较大时,测试结果可能恰恰相反。因此,为 了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。 对数阶 < 线性阶 < 线性对数阶 < 平方阶 < 指数阶 < 阶乘阶 图 2‑9 常见的时间复杂度类型 1. 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 第 2 章 复杂度分析 hello‑algo.com 31 在以下函数中,尽管操作数量 size 可能很大,但由于其与输入数据大小 ? 无关,因此时间复杂度仍为 ?(1) : // === 存储在同一链表中。图 6‑5 展示了一个链式地址哈希表的 例子。 第 6 章 哈希表 hello‑algo.com 117 图 6‑5 链式地址哈希表 哈希表在链式地址下的操作方法发生了一些变化。 ‧ 查询元素:输入 key ,经过哈希函数得到数组索引,即可访问链表头节点,然后遍历链表并对比 key 以 查找目标键值对。 ‧ 添加元素:先通过哈希函数访问链表头节点,然后将节点(即键值对)添加到链表中。0 码力 | 377 页 | 30.69 MB | 1 年前3
Hello 算法 1.0.0 C++版时间比算法 B 短;但在另一台配置不同的计算机中,可能得到相反的测试结果。这意味着我们需要在各种机 器上进行测试,统计平均效率,而这是不现实的。 另一方面,展开完整测试非常耗费资源。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入 数据量较小时,算法 A 的运行时间比算法 B 短;而在输入数据量较大时,测试结果可能恰恰相反。因此,为 了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。 < 阶乘阶 第 2 章 复杂度分析 hello‑algo.com 33 图 2‑9 常见的时间复杂度类型 1. 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 在以下函数中,尽管操作数量 size 可能很大,但由于其与输入数据大小 ? 无关,因此时间复杂度仍为 ?(1) : // === File: time_complexity.cpp === 同一链表中。图 6‑5 展示了一个链式地址哈希表的 例子。 图 6‑5 链式地址哈希表 第 6 章 哈希表 hello‑algo.com 122 基于链式地址实现的哈希表的操作方法发生了以下变化。 ‧ 查询元素:输入 key ,经过哈希函数得到桶索引,即可访问链表头节点,然后遍历链表并对比 key 以查 找目标键值对。 ‧ 添加元素:首先通过哈希函数访问链表头节点,然后将节点(键值对)添加到链表中。0 码力 | 378 页 | 17.59 MB | 1 年前3
Hello 算法 1.0.0b4 C++版A 的运行时 间比算法 B 短;但在另一台配置不同的计算机中,我们可能得到相反的测试结果。这意味着我们需要在各种 机器上进行测试,而这是不现实的。 展开完整测试非常耗费资源。随着输入数据量的变化,算法会表现出不同的效率。例如,输入数据量较小时, 算法 A 的运行时间可能短于算法 B;而输入数据量较大时,测试结果可能相反。因此,为了得到有说服力的 结论,我们需要测试各种规模的输入数据,这样需要占用大量的计算资源。 到不理解的部分,请不要担 心,可以在学习完后面章节后再回顾。现阶段,请先专注于理解时间复杂度的含义和推算方法。 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 对于以下算法,尽管操作数量 size 可能很大,但由于其与数据大小 ? 无关,因此时间复杂度仍为 ?(1) 。 2. 复杂度 hello‑algo.com 20 // === File: 对于密码学的相关应用,哈希算法需要满足更高的安全标准,以防止从哈希值推导出原始密码等逆向工程, 包括: ‧ 抗碰撞性:应当极其困难找到两个不同的输入,使得它们的哈希值相同。 ‧ 雪崩效应:输入的微小变化应当导致输出的显著且不可预测的变化。 请注意,“均匀分布”与“抗碰撞性”是两个独立的概念,满足均匀分布不一定满足抗碰撞性。例如,在随机 输入 key 下,哈希函数 key % 100 可以产生均匀分布的输出。然而该哈希算法过于简单,所有后两位相等的0 码力 | 343 页 | 27.39 MB | 1 年前3
《深入浅出MFC》2/e没有如期完成的原因是,MFC 本体架构并没有什么大改 变。《深入浅出MFC》2/e 书中所论之工具及程序代码虽采用VC5+MFC42,仍 适用于目前的VC6+MFC421(唯,工具之画面或功能可能有些微变化)。 由于《深入浅出MFC》2/e 并无简体版,因此我时时收到大陆读者来信询问购 买繁体版之管道。一来我不知道是否台湾出版公司有提供海外邮购或电购,二 来即使有,想必带给大家很大的麻烦,三来两岸消费水平之差异带给大陆读者 21。就在第五刷即将印行的 今天,Visual C++ 6.0 也已问世;其中的programming 关键,也就是MFC,在主干上没有什 么变化,因此我不打算为了Visual C++ 6.0 而改版。 在此新刷中,我继续修正了一些笔误,并加上新的读者来函。 未来,本书第三版,你会看到很大的变化。 侯俊杰台湾.新竹1998.09.11 jjhou@ccca.nctu.edu.tw FAX 886-3-5733976 Draw 和 CDocument::Serialize,这是两个极端重要之虚拟函数。 Scribble Step2-修改使用者接口(第9章):这个版本变化了菜单,使程序多 了笔宽设定功能。由于菜单的变化,也带动了工具栏与状态列的变化。 从这个版本中我们可以学习如何使用资源编辑器,制作各式各样的程序资源。为了把 菜单命令处理函数放置在适当的类别之中,我们需要深入了解所谓的Message0 码力 | 1009 页 | 11.08 MB | 1 年前3
现代C++ 教程:高速上手C++11/14/17/20stored_value == 1, 而 value == 100. // 因为 copy_value 在创建时就保存了一份 value 的拷贝 } 2. 引用捕获 与引用传参类似,引用捕获保存的是引用,值会发生变化。 void lambda_reference_capture() { int value = 1; 34 3.1 Lambda 表达式 第 3 章语言运行期的强化 auto copy_value 优化导致程序出错的情况 产生疑惑。例如,布尔值 notified 没有被 volatile 修饰,编译器可能对此变量存在优化,例如将其作 为一个寄存器的值,从而导致消费者线程永远无法观察到此值的变化。这是一个好问题,为了解释清楚 这个问题,我们需要进一步讨论从 C++ 11 起引入的内存模型这一概念。我们首先来看一个问题,下面 这段代码输出结果是多少? #include任何通信乃至本地操作都需要消耗一定时间,甚至出现不可靠的通信。 如果我们强行将一个变量 v 在多个线程之间的操作设为原子操作,即任何一个线程在操作完 v 后, 其他线程均能同步感知到 v 的变化,则对于变量 v 而言,表现为顺序执行的程序,它并没有由于引入多 线程而得到任何效率上的收益。对此有什么办法能够适当的加速呢?答案便是削弱原子操作的在进程间 的同步条件。 从原理上看,每个线程 0 码力 | 83 页 | 2.42 MB | 1 年前3
Hello 算法 1.0.0b1 C++版A 比算法 B 运行时间更短;但换到另一台配置不同的计算机中,可能会得到相反的测试结果。这意味着我们需要在各种机 器上展开测试,而这是不现实的。 展开完整测试非常耗费资源。随着输入数据量的大小变化,算法会呈现出不同的效率表现。比如,有可能输入 数据量较小时,算法 A 运行时间短于算法 B ,而在输入数据量较大时,测试结果截然相反。因此,若想要达 到具有说服力的对比结果,那么需要输入各种体 如果遇到看不懂的地方无需担心, 可以在学习完后面章节后再来复习,现阶段先聚焦在理解时间复杂度含义和推算方法上。 常数阶 ?(1) 常数阶的操作数量与输入数据大小 ? 无关,即不随着 ? 的变化而变化。 对于以下算法,无论操作数量 size 有多大,只要与数据大小 ? 无关,时间复杂度就仍为 ?(1) 。 // === File: time_complexity.cpp === /* 常数阶 hello‑algo.com 128 i = p; } } 堆顶元素出堆 堆顶元素是二叉树根结点,即列表首元素,如果我们直接将首元素从列表中删除,则二叉树中所有结点都会随 之发生移位(索引发生变化),这样后续使用堆化修复就很麻烦了。为了尽量减少元素索引变动,采取以下操 作步骤: 1. 交换堆顶元素与堆底元素(即交换根结点与最右叶结点); 2. 交换完成后,将堆底从列表中删除(注意,因为0 码力 | 187 页 | 14.71 MB | 1 年前3
共 15 条
- 1
- 2













