C语言中const对象指针的隐式与显式转换合规性问询
多步指针强制转换的合规性问题
看这段代码:
int const i = 0; int const *p = &i; // ok int const *t = (int const *)(float *)(int *)&i; // 是合规还是UB?
从C标准的规则来看:
- 指针的显式类型转换本身是允许的(C17 6.3.2.3),只要不是函数指针与对象指针之间的跨域转换。这里的多步转换只是改变了指针的类型标记,并没有通过中间的
(int *)&i或(float *)&i对i进行任何读/写访问操作。 - 最终
t的类型是int const*,和i的const int类型完全匹配,通过t访问i完全符合标准要求。
结论:这段代码是合规的,不存在未定义行为。中间的转换步骤仅为类型转换操作,未涉及对const对象的非法访问,因此是安全的。
函数传参丢失const中间步骤的安全性问题
对于调用send((unsigned int *)&s, sizeof(s));是否和send((unsigned int const *)&s, sizeof(s));一样安全的疑问:
结合C标准的具体条款分析:
- 结构体指针转首元素指针是合法的:C17 6.7.2.1明确规定,结构体对象的指针可合法转换为其首成员的指针。这里
Str的第一个成员是unsigned int,所以&s转成unsigned int*或unsigned int const*都满足对齐要求,完全合规。 - 限定符转换的规则:
- C17 6.3.2.3允许显式将const对象的指针转换为非限定类型的指针(比如
const Str*转unsigned int*),但禁止通过该非限定指针修改const对象。 send的参数是unsigned int const buf[](等价于unsigned int const*),传递unsigned int*时会自动隐式转换为unsigned int const*——这是标准允许的隐式添加const限定的操作。
- C17 6.3.2.3允许显式将const对象的指针转换为非限定类型的指针(比如
- 未定义行为风险:整个过程中,我们没有用临时的
unsigned int*指针去读/写const Str s,send内部也是通过const指针操作,完全不会触及const对象的非法修改或访问。
结论:两种调用方式完全一样安全。前者虽然在转换中间临时丢失了const限定,但只要未通过非限定指针操作const对象,且最终传给函数的是const限定的指针,就完全符合标准,不会产生未定义行为。
内容的提问来源于stack exchange,提问作者Evgeny Ilyin
相关产品推荐
相关产品推荐

