|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: 第183期 |
| 4 | +--- |
| 5 | +# C++ 中文周刊 2025-05-19 第183期 |
| 6 | + |
| 7 | + |
| 8 | +[周刊项目地址](https://github.com/wanghenshui/cppweeklynews) |
| 9 | + |
| 10 | +公众号 |
| 11 | + |
| 12 | +<img src="https://wanghenshui.github.io/cppweeklynews/assets/code.png" alt="" width="30%"> |
| 13 | + |
| 14 | +点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了 |
| 15 | + |
| 16 | +qq群 753792291 答疑在这里 |
| 17 | + |
| 18 | +[RSS](https://github.com/wanghenshui/cppweeklynews/releases.atom) |
| 19 | + |
| 20 | +欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言 |
| 21 | + |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## 资讯 |
| 26 | + |
| 27 | +标准委员会动态/ide/编译器信息放在这里 |
| 28 | + |
| 29 | +[编译器信息最新动态推荐关注hellogcc公众号 本周更新 2025-01-08 第288期](https://mp.weixin.qq.com/s/jMaR7QyCD40uCAKJSyLw6A) |
| 30 | + |
| 31 | +[性能周刊](https://mp.weixin.qq.com/s/rkoBXmzhrbhvN4AEmBHS7w) |
| 32 | + |
| 33 | + |
| 34 | +## 文章 |
| 35 | + |
| 36 | +### [C++26: constexpr exceptions](https://www.sandordargo.com/blog/2025/05/07/cpp26-constexpr-exceptions) |
| 37 | + |
| 38 | + |
| 39 | +优化异常constexpr化,不能constexpr的编译期报错,加固代码降低UB,同时降低异常开销,好事 |
| 40 | + |
| 41 | +### [C++20 concepts for nicer compiler errors](https://lemire.me/blog/2025/05/03/c20-concepts-for-nicer-compiler-errors/) |
| 42 | + |
| 43 | +concept编译模版报错更易懂 |
| 44 | + |
| 45 | +### [An option(al) to surprise you](https://andreasfertig.com/blog/2025/05/an-optional-to-surprise-you/) |
| 46 | + |
| 47 | +```cpp |
| 48 | +enum class State { |
| 49 | + Initial, |
| 50 | + WaitingForInput, |
| 51 | + GotValidInput, |
| 52 | + GotValidInputWithData, |
| 53 | + GotInvalidInput |
| 54 | +}; |
| 55 | + |
| 56 | +std::optional<const char*> Worker(State s, const char* data) { |
| 57 | + switch(s) { |
| 58 | + using enum State; |
| 59 | + case Initial: return std::nullopt; |
| 60 | + case WaitingForInput: return {}; |
| 61 | + case GotValidInput: [[fallthrough]]; |
| 62 | + case GotValidInputWithData: return data; |
| 63 | + case GotInvalidInput: return ""; |
| 64 | + } |
| 65 | + |
| 66 | + return std::nullopt; |
| 67 | +} |
| 68 | +``` |
| 69 | +
|
| 70 | +幽默代码 这个例子里 optional有点类似optinal<T*> 存指针也就有可能存nullptr,导致误用报错。坏实践 |
| 71 | +
|
| 72 | +
|
| 73 | +### [如何算闰年](https://hueffner.de/falk/blog/a-leap-year-check-in-three-instructions.html) |
| 74 | +
|
| 75 | +传统算法 |
| 76 | +```c++ |
| 77 | +bool is_leap_year(uint32_t y) { |
| 78 | + if ((y % 4) != 0) return false; |
| 79 | + if ((y % 100) != 0) return true; |
| 80 | + if ((y % 400) == 0) return true; |
| 81 | + return false; |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +显然,能继续优化 |
| 86 | +```c++ |
| 87 | +bool is_leap_year1(uint32_t y) { |
| 88 | + if ((y % 4) != 0) return false; |
| 89 | + if ((y % 25) != 0) return true; |
| 90 | + if ((y % 16) == 0) return true; |
| 91 | + return false; |
| 92 | +} |
| 93 | +``` |
| 94 | +
|
| 95 | +我们考虑去掉mod |
| 96 | +```c++ |
| 97 | +bool is_leap_year2(uint32_t y) { |
| 98 | + if ((y & 3) != 0) return false; |
| 99 | + if (y * 3264175145u > 171798691u) return true; |
| 100 | + if ((y & 15) == 0) return true; |
| 101 | + return false; |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +第二行有点令人费解 我们考虑通过定点缩放来去掉mod |
| 106 | + |
| 107 | +我们需要找到一个分数来近似表示 1/25 |
| 108 | + |
| 109 | +在32位无符号整数中,我们可以用 m/2^32 来近似 1/25 |
| 110 | + |
| 111 | +通过计算得知 2^32 / 25 = 171798691.84 |
| 112 | +所以我们取 m = 171798692 作为近似值 |
| 113 | +因此,对于任意数x: |
| 114 | + |
| 115 | +(x * 171798692) / 2^32 近似等于 x/25 |
| 116 | +如果x是25的倍数,则结果是一个整数 |
| 117 | +如果x不是25的倍数,则结果有小数部分 |
| 118 | +在32位计算中,乘法 x * 171798692 的高32位实际上就是 (x * 171798692) / 2^32 |
| 119 | + |
| 120 | +要检查x是否为25的倍数,我们需要判断这个结果是否为整数,但实际上我们要的是相反的结果(不是25的倍数) |
| 121 | + |
| 122 | +通过将问题转化为检查 x * 3264175145u > 171798691u,我们实际上在检查: |
| 123 | + |
| 124 | +3264175145是2^32 - 171798692 + 1的补码 |
| 125 | +这个比较操作效果上等同于检查x不是25的倍数 |
| 126 | +为什么用3264175145而不是171798692? |
| 127 | + |
| 128 | +这里的关键是编译器优化中使用的技巧。不是直接计算 x * 171798692 / 2^32,而是通过计算 x * (2^32 - 1) / 25 + 1 来达到同样的效果。 |
| 129 | + |
| 130 | +具体计算: |
| 131 | +(2^32 - 1) / 25 = 171798691.96 |
| 132 | +取近似值为3264175145 |
| 133 | +当我们用x乘以这个数时,对于25的倍数,结果恰好落在某个特定范围内,使得 x * 3264175145u > 171798691u 正好对应 x % 25 != 0 |
| 134 | + |
| 135 | +但是这种编译器也能优化,属于过度优化,我们考虑分支优化 |
| 136 | + |
| 137 | +```cpp |
| 138 | +bool is_leap_year3(uint32_t y) { |
| 139 | + return !(y & ((y % 25) ? 3 : 15)); |
| 140 | +} |
| 141 | +``` |
| 142 | +
|
| 143 | +性能比上面的要好 |
| 144 | +
|
| 145 | +
|
| 146 | +作者考虑第二种算术优化和分支优化的结合版本 |
| 147 | +
|
| 148 | +作者是用求解器硬算的,考虑构造 ((y * f) & m) <= t格式,然后求解器算出满足条件的f m t |
| 149 | +
|
| 150 | +```python |
| 151 | +import z3 |
| 152 | +
|
| 153 | +BITS = 32 |
| 154 | +f, m, t, y = z3.BitVecs('f m t y', BITS) |
| 155 | +
|
| 156 | +def target(y): |
| 157 | + return z3.And((y & 3) == 0, z3.Or(z3.URem(y, 25) != 0, (y & 15) == 0)) |
| 158 | +
|
| 159 | +def candidate(x): |
| 160 | + return z3.ULE((x * f) & m, t) |
| 161 | +
|
| 162 | +solver = z3.Solver() |
| 163 | +solver.add(z3.ForAll(y, z3.Implies(z3.ULE(y, 400), |
| 164 | + candidate(y) == target(y)))) |
| 165 | +
|
| 166 | +if solver.check() == z3.sat: |
| 167 | + print(f'found solution: {solver.model()}') |
| 168 | +else: |
| 169 | + print('no solution found') |
| 170 | +``` |
| 171 | + |
| 172 | +### [The case of the UI thread that hung in a kernel call](https://devblogs.microsoft.com/oldnewthing/20250411-00/?p=111066) |
| 173 | + |
| 174 | +不要在进程内挂起线程。自己给自己搞死锁。感谢 YexuanXiao投稿 |
| 175 | + |
| 176 | +### [Load-store conflicts](https://zeux.io/2025/05/03/load-store-conflicts/) |
| 177 | + |
| 178 | +非常好的文章 多版本编译器压测对比才发现问题所在 |
| 179 | + |
| 180 | +数据存在存储加载冲突,导致性能瓶颈,这种通过汇编是看不出来的,得对比压测才能看出来 |
| 181 | + |
| 182 | +## 视频 |
| 183 | + |
| 184 | +### [File IO - Past, Present and Future - Guy Davidson - ACCU 2024 ](https://www.youtube.com/watch?v=fNwVRGnM3Ls&list=PL9hrFapz4dsMFj78AiNheJV2tFBgK_FbC&index=18) |
| 185 | + |
| 186 | +大部份都在讲历史,然后讲一段#embed 和提案相关的file handle之类的设计 |
| 187 | + |
| 188 | +### [Understanding the Filter View to Use It Right - Nicolai M. Josuttis - ACCU 2024 ](https://www.youtube.com/watch?v=jR3WE-hAhCc&list=PL9hrFapz4dsMFj78AiNheJV2tFBgK_FbC&index=12) |
| 189 | + |
| 190 | +filter view由于缓存性质多了很多坑,主要是讲使用细节 |
| 191 | + |
| 192 | +### [Narrow Contracts and noexcept are Inherently Incompatible in C++ - John Lakos - ACCU 2024 ](https://www.youtube.com/watch?v=VCwC1cvP8i0&list=PL9hrFapz4dsMFj78AiNheJV2tFBgK_FbC&index=10) |
| 193 | + |
| 194 | +Narrow contract和noexcept不兼容 |
| 195 | + |
| 196 | +什么?你不知道narrow contract是什么?翻出contract概念复习一下 |
| 197 | + |
| 198 | +## 开源项目介绍 |
| 199 | + |
| 200 | +- [asteria](https://github.com/lhmouse/asteria) 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线 |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | +## 互动环节 |
| 205 | + |
| 206 | +--- |
| 207 | + |
| 208 | +[上一期](https://wanghenshui.github.io/cppweeklynews/posts/182.html) |
| 209 | + |
| 210 | +[本期](https://wanghenshui.github.io/cppweeklynews/posts/183.html) |
| 211 | + |
0 commit comments