在指向数组转换的指针的上下文中,有人可以解释为什么这些转换是合法的还是非法的?

时间:2017-08-02 09:12:33

标签: c++ arrays pointers casting

了解(多维)数组/指针转换的知识,以下两条规则可以解释一些非法转换:

  1. T[M][N]拒绝T(*)[N],而不是T**(如this SO entry中所述)
  2. 没有从T**const T**的隐式转换(如the C++ faq中所述)
  3. 所以这里是一些试图覆盖不同情况的测试代码。我们无法解释的3个案例用P1,P2和P3注释。

    int main() {
        {
            int arrayOfInt[3] = {0, 1, 2};
            int * toPtr{nullptr};
            int ** toPtrPtr{nullptr};
            const int ** toPtrPtrConst{nullptr};
    
    
            toPtr = arrayOfInt;
    
            //toPtrPtr = &arrayOfInt; //KO, I assume because of 1.
            //toPtrPtr = static_cast<int**>(&arrayOfInt); //KO, same as above
            toPtrPtr = reinterpret_cast<int**>(&arrayOfInt);
            toPtrPtr = (int**)&arrayOfInt;
    
            //toPtrPtrConst = &arrayOfInt; //KO, still 1.
            //toPtrPtrConst = static_cast<const int**>(&arrayOfInt); //KO, still 1.
            toPtrPtrConst = reinterpret_cast<const int**>(&arrayOfInt); // (P1)
                // it is supposed to be allowed to cast int** to const int* const*
                // not const int**
                // Why is it working without requiring a const_cast
                // to cast away the const qualifier?
            toPtrPtrConst = (const int**)&arrayOfInt;
    
            //toPtrPtrConst = toPtrPtr; //KO, because of 2.
            //toPtrPtrConst = reinterpret_cast<const int**>(toPtrPtr); //KO because of 2.
                // so why is P1 allowed?
        }
    
        {
            const int arrayOfConstInt[3] = {0, 1, 2};
            const int * toPtrConst{nullptr};
            const int ** toPtrPtrConst{nullptr};
            int * const * toPtrConstPtr{nullptr};
    
            toPtrConst = arrayOfConstInt;
    
            //toPtrPtrConst = &arrayOfConstInt; //KO, I assume because of 1.
            //toPtrPtrConst = static_cast<const int**>(&arrayOfConstInt); //KO, same as above
            //toPtrPtrConst = reinterpret_cast<const int**>(&arrayOfConstInt); // (P2) 
                // Compiler error "casts away qualifiers",
                // but which qualifier(s) would that cast away?
            toPtrPtrConst = (const int**)&arrayOfConstInt;
    
            //toPtrConstPtr = &arrayOfConstInt; //KO, I assume because of 1.
            //toPtrConstPtr = static_cast<int * const *>(&arrayOfConstInt); //KO, same as above
            toPtrConstPtr = reinterpret_cast<int * const *>(&arrayOfConstInt); // (P3) 
                // This one actually drops the const qualifier on the integer,
                // but nevertheless it compiles
            toPtrConstPtr = (int * const *)&arrayOfConstInt;
    
            toPtrConstPtr = reinterpret_cast<int * const *>(&toPtrConst); // KO
                // because it casts away const qualifier
                // so why is P3 allowed?
        }
    }
    

    这里是ideone:http://ideone.com/JzWmAJ

    • 为什么P1允许,但似乎违反了2。?
    • P2弃掉的限定符是什么?
    • 为什么在实际转换const限定符时允许P3?

3 个答案:

答案 0 :(得分:2)

  1. 明确的类型转换(又名&#34;演员&#34;)并没有违反有关隐式类型转化的规则,因为关于隐式类型转化的规则对每个人来说都是不足为奇的,不适用显式类型转换。
  2. const int (*)[3]是一种指向常量的东西(其中&#34;某些东西&#34;是int[3]),而const int**是一种指针-to-non-constant-something(其中&#34;某些东西&#34;是指向const int的指针)。指针到常量的常量被剥离,这是不允许的。
  3. 没有限定符被删除。 toPtrConstPtr是一个指向常量的东西(某些东西是int *)而&arrayOfConstInt是一个指向常量的东西(某些东西是int[3])。
  4. 应该指出的是,这是严格的语言律师材料。没有普通的程序员应该允许任何这些演员在他们的代码附近。

答案 1 :(得分:1)

代码中的所有演员阵容都很糟糕,包括那些你没有标记为坏的演员。

如果你这样做:

cout << (uintptr_t)arrayOfInt << "\n";
cout << (uintptr_t)toPtrPtr << "\n";

你会发现输出是相同的。这是因为&arrayOfInt的类型为int (*)[3]。当您使用*&arrayOfInt取消引用它时,您将得到一个数组,该数组将衰减回类型为int*的指针,其二进制值与您取消引用的指针相同。但是,当您取消引用int**时,您将从内存中加载一些位,这些位将是解除引用的指针。这两种解除引用从根本上说是不相容的。确实没有假装int (*)[3]int**相同。

答案 2 :(得分:0)

T[N]有时被视为单一类型,因为您使用的模板类如std::array<T, N>std::tuple<int, char, std::string>,因此它被视为单个变量。例如。 jmp_buf <csetjmp>是一个数组,但它像普通变量一样使用。因此,当您在T[M][N]中使用固定数组时,当您为每个元素编写成员时,它是一个类型为T的N * M个元素的线性块一个结构,而指向指针的指针需要多个内存块,一个内存块用于指向元素的指针和指针指向的每个数组的内存。但是,没有固定边界的数组(如T[])会被视为T*。当你在一个数组中使用const T时,它的工作方式与T本身不同,所以你可以c-cast一个任何类型的数组,如果它是const,你怎么可以转换{ {1}}到char*,c ++是严格的并检查const。取消引用的arrayOfInt是r值,reinterpret_cast有时会出现r值问题。将解除引用的变量存储在单独的变量中然后使用与引用相同的类型重新解释它应该有效。