C++标准是否保证三种间接访问方式的行为均定义良好?
三种C++间接访问方式的标准合规性验证
问题背景
我实现了三种间接访问修改int变量的方式,测试了[[gnu::always_inline]] inline和[[gnu::noinline]]两种编译选项,输出均为10 12 14,想确认这三种方式是否均为C++标准定义的良好行为,可安全用于跨平台代码——尤其需要考虑**类型别名分析(Type-Based Alias Analysis, TBAA)**的影响。
测试代码如下:
#include <cstdint> #include <iostream> #include <any> using namespace std; #if 1 #define INLINE [[gnu::always_inline]] inline #else #define INLINE [[gnu::noinline]] #endif INLINE void mod1(void *p) { *static_cast<int*>(p) = 10; } INLINE void mod2(uintptr_t p) { *reinterpret_cast<int*>(p) = 12; } INLINE void mod3(any p) { *any_cast<int*>(p) = 14; } int test1() { int a1 = 5; mod1(&a1); return a1; } int test2() { int a2 = 6; mod2(reinterpret_cast<uintptr_t>(&a2)); return a2; } int test3() { int a3 = 6; mod3(&a3); return a3; } int main() { cout << test1() << "\n"; cout << test2() << "\n"; cout << test3() << "\n"; }
三种方式的标准合规性分析
1. mod1:void*转int*的访问
这种方式完全符合C++标准:
- C++标准明确允许:将指向对象的指针转换为
void*,再通过static_cast转换回原类型指针,得到的指针与原指针等价,可安全用于访问原对象。 - 从TBAA角度看,最终解引用的是原类型
int的指针,严格遵守类型别名规则(strict aliasing rule)——规则允许通过原类型指针访问对象,因此不会触发TBAA导致的未定义行为。
2. mod2:uintptr_t中转的指针访问
这种方式也是定义良好的:
- 标准规定,
uintptr_t(主流平台均支持,属于可选实现但几乎全平台提供)是一种无符号整数类型,能完整容纳void*的值。将int*转换为void*再转成uintptr_t,随后通过reinterpret_cast转回int*,得到的指针与原指针等价。 - TBAA层面,最终同样是通过
int*访问原int对象,符合strict aliasing规则,不存在未定义行为。
3. mod3:std::any中转的指针访问
这种方式同样符合标准:
std::any的设计目标就是存储任意类型的对象(包括指针),传入int*时,std::any会保存该指针的类型信息。any_cast<int*>(p)在类型匹配时会返回正确的int*(类型不匹配时会抛出bad_any_cast异常,但此处传入的确实是int*,因此不会触发异常),解引用该指针修改原int对象完全合规。- TBAA角度,同样是通过原类型指针访问,无违规问题。
关于内联的补充
你测试的内联/非内联选项不影响结果,这是符合预期的:无论函数是否被内联,C++标准对指针转换、对象访问的规则都是强制性的,编译器必须保证这些操作的行为一致性。
内容的提问来源于stack exchange,提问作者Home of the Brave
相关产品推荐
相关产品推荐

