了解(多维)数组/指针转换的知识,以下两条规则可以解释一些非法转换:
T[M][N]
拒绝T(*)[N]
,而不是T**
(如this SO entry中所述)T**
到const T**
的隐式转换(如the C++ faq中所述)所以这里是一些试图覆盖不同情况的测试代码。我们无法解释的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
答案 0 :(得分:2)
const int (*)[3]
是一种指向常量的东西(其中&#34;某些东西&#34;是int[3]
),而const int**
是一种指针-to-non-constant-something(其中&#34;某些东西&#34;是指向const int
的指针)。指针到常量的常量被剥离,这是不允许的。toPtrConstPtr
是一个指向常量的东西(某些东西是int *
)而&arrayOfConstInt
是一个指向常量的东西(某些东西是int[3]
)。 应该指出的是,这是严格的语言律师材料。没有普通的程序员应该允许任何这些演员在他们的代码附近。
答案 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值问题。将解除引用的变量存储在单独的变量中然后使用与引用相同的类型重新解释它应该有效。