首页 > 解决方案 > 关于将指向 char 的指针转换为另一种类型指针的问题

问题描述

#include <iostream>
struct Test{
   int a;
   int b;
};
int main(){
  char* buffer = (char*)malloc(sizeof(char)*32);  //#a
  char* ptr = buffer + 4;  //#b
  new(ptr) Test;  //#c
  char* ptr2 = buffer + 4;  //#d
  Test* tptr = reinterpret_cast<Test*>(ptr2);  //#e
  tptr->a = 1; // #f
}

考虑上面的代码,在点 处#a,分配函数malloc分配一个存储区域并隐式创建一个类型为 的数组对象char[32],这在以下规则中有所提及:

一些操作被描述为在指定的存储区域内隐式创建对象。对于指定为隐式创建对象的每个操作,该操作会在其指定的存储区域中隐式创建并启动零个或多个隐式生命周期类型([basic.types])的对象的生命周期,如果这样做会导致程序有明确的行为。如果没有这样的对象集会给程序定义的行为,则程序的行为是未定义的。如果多个这样的对象集会给程序定义的行为,则未指定创建哪个这样的对象集。

所以, at 的代码#b定义得很好,因为指针buffer可以被认为是指向数组的第一个元素,它满足规则expr.add#4。at的代码#c也很好定义,它将在ptr指向的存储处构造一个Test类型的对象。#d与 相同#b,也很好定义。

但是,请考虑#e. 现在,指针指向(由 )创建ptr2的第四个元素,该元素是 char 类型的对象,其生命周期由于其存储而结束,被 类型的对象重用。表达式等价于。arraymallocTestreinterpret_cast<Test*>(ptr2)static_cast<Test*>(static_cast<void*>(ptr2))

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定或大于 cv1 的 cv 限定。如果原始指针值表示内存中一个字节的地址A,并且A不满足T的对齐要求,那么得到的指针值是未指定的。否则,如果原始指针值指向对象 a,并且存在与 a 指针可互转换的类型为 T(忽略 cv 限定)的对象 b,则结果是指向 b 的指针。否则,指针值不会因转换而改变。

根据上述规则,类型的对象Test不能与 char 类型的对象进行指针互转换。所以,我认为结果仍然是指向 char 类型对象的指针,它是数组的第四个元素,只是它的生命周期已经结束。

所以,我想知道#f由于tptr不指向类型的对象,代码是否具有未定义的行为Test?或者相反,指针是否tptr确实指向类型的对象Test并且代码定义明确?如果我错过了其他一些规则,请指出。

标签: c++language-lawyerc++20

解决方案


#f由于tptr不指向类型的对象,代码是否具有未定义的行为Test

该程序具有未定义的行为,因为#a, 因为malloc被定义为触发隐式对象创建并返回指向合适的已创建对象的指针,但是将为程序的其余部分提供定义行为的对象集是空的。


推荐阅读