如何在c++运行时声明n阶指针

How to declare n-th order pointers in runtime in C++

本文关键字:指针 声明 运行时 c++      更新时间:2023-10-16

指针可以这样声明:

int
    a = 1,
    *b = &a,      // 1st order pointer
    **c = &b,     // 2nd order pointer
    ***d = &c,    // 3rd order pointer
    ****e = &d,   // 4th order pointer
    *****f = &e,  // 5th order pointer
    *** n-stars *** f;  // n-th order pointer

这里,在声明指针时,需要在编译时知道指针的顺序。是否有可能声明一个指针,其顺序只在运行时知道?链接到这个问题是是否有可能在运行时查询任意指针的顺序?

int order = GET_ORDER_OF_PTR(f) // returns 5
int /* insert some syntax here to make ptr a pointer of order (order + 1) */ ptr = &f;

注意:我已经知道这(通常)可能不是一个好主意。还是想知道它是否可行:)

在运行时你不能——因为c++是静态类型的。在编译过程中,可以使用模板,例如

template<typename T, int order> struct P
{
  typedef typename P<T, order-1>::pointer* pointer;
};
template<typename T> struct P<T, 0>
{
  typedef T pointer;
};

P<int, 3>::pointer等价于int***

你不能。c++是静态类型的,所以指针的顺序(这是其类型的一部分)必须在编译时知道。

不能在C或c++中使用,因为它们是静态类型语言(即存储在变量中的值的类型在编译时是已知的并且是固定的)。

您可以通过定义一个c++类 来模拟这种可能性。
template<typename T>
struct NPtr {
    int order;
    void *p;  // order 0 -> T*, otherwise NPtr<T>*
    NPtr(NPtr *ptr) : islast(ptr->order+1), p(ptr) {}
    NPtr(T *final) : islast(0), ptr(final) {}
    NPtr<T>& nptr() {
        assert(order > 0);
        return *(NPtr<T>*)p;
    }
    T& final() {
        assert(order == 0);
        return *(T*)p;
    }
};

TPtr<int>实例可以是指向整数的指针(当order=0时),也可以是指向另一个TPtr<int>实例的指针。

您想要的语义等效是一个链表,在运行时确定节点数量:

#include <iostream>
union kind_of_pointer
{
  int data;
  kind_of_pointer *next;
  kind_of_pointer(int val) : data(val) {}
  kind_of_pointer(kind_of_pointer* ptr) : next(ptr) {}
  operator int()
  {
    return data;
  }
  kind_of_pointer& operator *()
  {
    return *next;
  }    
};
int     main(void)
{
  kind_of_pointer dyn_ptr{new kind_of_pointer{new kind_of_pointer{new kind_of_pointer{42}}}};
  int***          static_ptr = new int**{new int *{new int{42}}};
  std::cout << ***dyn_ptr << std::endl;
  std::cout << ***static_ptr << std::endl;
}

我觉得这很有趣,很有趣,也很可怕。

你可以这样做:

int *f = nullptr;
decltype(f) *newptr = 0;

至于

是否可以在运行时查询任意序列的顺序指针?

部分:不,你绝对不能,除非你编写自己的包装器类来存储指针的顺序。指针基本上是一个数字:内存中的地址。

这给了你至少一个问题:你不能跟随指针"所有的方式"(你必须做的是检查你的指针指向的东西本身是一个指针),而没有潜在地导致段错误或读取"不是你的应用程序的内存"(这通常被操作系统禁止,并将导致你的应用程序被中止;不确定你是否能阻止这种情况)。

例如,

可以将NULL(或0)强制转换为任何指针类型,因此它本身就是一个指针。但是它指向另一个指针吗?让我们来看看……砰!段错误。

哦,等等,还有另一个问题:您可以(使用c风格的强制转换或reinterpret_cast)将任何类型的指针强制转换为任何其他类型的指针。例如,a可能指向一个指针,但被强制转换为不同的类型。或者a可能有一个"指向指针"的类型,但实际上并没有指向指针。

注:很抱歉,动词"point"用得太随意了。

…在编译时声明指针时,需要知道指针的顺序。

是的,可以在编译时确定声明的指针类型的顺序;基于类型(可能通过typedef)或变量,如果c++ 11可以使用(通过decltype())

#include <iostream>
using namespace std;
template <typename P>
struct ptr_order
{
  static const int order = 0;
};
template <typename P>
struct ptr_order<P*>
{
  static const int order = ptr_order<P>::order + 1;
};
int main()
{
  typedef int*** pointer;
  cout << ptr_order<pointer>::order << endl; // outputs 3
  // could also use decltype if available...
  // int*** p;
  // ptr_order<decltype(p)>::order is also 3
}

运行时计算指针的顺序是不可能的,因为c++是静态类型的。