Skip to content

Commit 78bed5e

Browse files
committed
book: add type punning (memcpy/bit_cast) and math special functions
Section 9.5 explains why reinterpret_cast-based type punning is UB (strict aliasing) and shows the correct std::memcpy and C++20 std::bit_cast approaches (compiled example code/9/9.5). Section 9.6 documents the C++17 special math functions, with an explicit caveat that libc++ historically lacks them (so no compiled example). Refs #1
1 parent 2a1d21f commit 78bed5e

3 files changed

Lines changed: 108 additions & 0 deletions

File tree

book/en-us/09-others.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,43 @@ Aligned* p = new Aligned; // C++17: automatically uses the aligned operator new
205205
delete p;
206206
```
207207

208+
## 9.5 Type punning and `std::bit_cast`
209+
210+
"Type punning" means reinterpreting the same memory as a different type, common in low-level code (e.g. reading the bit pattern of a floating-point number). Many people reach for `reinterpret_cast` through a pointer or reference:
211+
212+
```cpp
213+
float f = 3.14f;
214+
std::uint32_t bits = *reinterpret_cast<std::uint32_t*>(&f); // undefined behavior!
215+
```
216+
217+
But this violates the **strict-aliasing rule**: except through `char`, `unsigned char`, or `std::byte`, accessing an object via an lvalue of a type incompatible with the object's actual type is undefined behavior, and the optimizer is free to assume it never happens.
218+
219+
The correct, portable approach is `std::memcpy` (valid under any standard):
220+
221+
```cpp
222+
std::uint32_t bits;
223+
std::memcpy(&bits, &f, sizeof bits); // well-defined
224+
```
225+
226+
C++20 further provides `std::bit_cast` (in `<bit>`), which reinterprets the object representation in a well-defined way with clearer semantics and can be used in constant expressions:
227+
228+
```cpp
229+
#include <bit>
230+
auto bits = std::bit_cast<std::uint32_t>(f); // both types must be the same size and trivially copyable
231+
float back = std::bit_cast<float>(bits);
232+
```
233+
234+
## 9.6 Mathematical special functions
235+
236+
C++17 added a set of mathematical special functions to `<cmath>` — such as `std::riemann_zeta`, `std::beta`, `std::assoc_legendre`, and `std::cyl_bessel_j` — useful in scientific computing and machine-learning related domains:
237+
238+
```cpp
239+
#include <cmath>
240+
double z = std::riemann_zeta(2.0); // ~ 1.6449 (i.e. pi^2 / 6)
241+
```
242+
243+
> Note that although these special functions are part of the standard, **standard-library support varies**: libstdc++ (GCC) provides a complete implementation, while libc++ (Clang) did not implement them for a long time. The code above therefore may not compile on every toolchain; check your standard library's support before using them.
244+
208245
## Conclusion
209246

210247
Several of the features introduced in this section are those that

book/zh-cn/09-others.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,43 @@ Aligned* p = new Aligned; // C++17:自动使用对齐版本的 operator new
193193
delete p;
194194
```
195195

196+
## 9.5 类型双关与 `std::bit_cast`
197+
198+
「类型双关」(type punning) 指的是把同一段内存按另一种类型重新解读,常见于底层编程(例如读取浮点数的位模式)。许多人习惯用 `reinterpret_cast` 通过指针或引用来做这件事:
199+
200+
```cpp
201+
float f = 3.14f;
202+
std::uint32_t bits = *reinterpret_cast<std::uint32_t*>(&f); // 未定义行为!
203+
```
204+
205+
但这违反了**严格别名规则 (strict aliasing rule)**:除了 `char``unsigned char``std::byte` 之外,通过与对象实际类型不兼容的左值去访问该对象是未定义行为,编译器在优化时完全可以假设这种情况不会发生。
206+
207+
正确且可移植的做法是使用 `std::memcpy`(在任何标准下都合法):
208+
209+
```cpp
210+
std::uint32_t bits;
211+
std::memcpy(&bits, &f, sizeof bits); // 良好定义
212+
```
213+
214+
C++20 进一步提供了 `std::bit_cast`(位于 `<bit>`),它以良好定义的方式重新解读对象表示,语义更清晰,并且可以用于常量表达式:
215+
216+
```cpp
217+
#include <bit>
218+
auto bits = std::bit_cast<std::uint32_t>(f); // 要求两个类型大小相同且可平凡复制
219+
float back = std::bit_cast<float>(bits);
220+
```
221+
222+
## 9.6 数学特殊函数
223+
224+
C++17 在 `<cmath>` 中引入了一组数学特殊函数(special mathematical functions),例如 `std::riemann_zeta``std::beta``std::assoc_legendre``std::cyl_bessel_j` 等,便于科学计算与机器学习相关领域使用:
225+
226+
```cpp
227+
#include <cmath>
228+
double z = std::riemann_zeta(2.0); // ≈ 1.6449 (即 π²/6)
229+
```
230+
231+
> 需要注意的是,这些特殊函数属于标准的一部分,但**各标准库实现的支持程度不一**:libstdc++ (GCC) 提供了完整实现,而 libc++ (Clang) 在很长时间内并未实现它们。因此上面的代码不一定能在所有工具链上编译,使用前请确认你的标准库支持情况。
232+
196233
## 总结
197234

198235
本节介绍的几个特性是从仍未介绍的现代 C++ 新特性里使用频次较靠前的特性了,`noexcept` 是最为重要的特性,它的一个功能在于能够阻止异常的扩散传播,有效的让编译器最大限度的优化我们的代码。

code/9/9.5.type.punning.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// 9.5.type.punning.cpp
3+
// chapter 09 others
4+
// modern c++ tutorial
5+
//
6+
// created by changkun at changkun.de
7+
// https://github.com/changkun/modern-cpp-tutorial
8+
//
9+
10+
#include <bit>
11+
#include <cstdint>
12+
#include <cstring>
13+
#include <iostream>
14+
15+
int main() {
16+
float f = 3.14f;
17+
18+
// Reinterpreting an object's bytes via a different type through a
19+
// pointer/reference cast violates the strict-aliasing rule and is
20+
// undefined behavior:
21+
// std::uint32_t bad = *reinterpret_cast<std::uint32_t*>(&f); // UB
22+
23+
// Portable and always-valid approach (any standard): std::memcpy.
24+
std::uint32_t bits;
25+
std::memcpy(&bits, &f, sizeof bits);
26+
27+
// C++20: std::bit_cast does the same well-defined reinterpretation
28+
// and is usable in constant expressions.
29+
auto bits2 = std::bit_cast<std::uint32_t>(f);
30+
31+
std::cout << std::hex << bits << " == " << bits2 << std::dec
32+
<< " : " << (bits == bits2) << "\n";
33+
std::cout << "round-trip: " << std::bit_cast<float>(bits2) << "\n";
34+
}

0 commit comments

Comments
 (0)