Рассмотрим следующий код:
int main() {
int (*p)[]; // pointer to array with unspecified bounds
int a[] = {1};
int b[] = {1,2};
p = &a; // works in C but not in C++
p = &b; // works in C but not in C++
return 0;
}
В чистом C вы можете назначить указатель на этот тип адреса массива любого измерения. Но в C ++ вы не можете. Я нашел один случай, когда компилятор позволяет присваивать значение такому указателю:
struct C
{
static int v[];
};
int main()
{
int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
return 0;
}
Но не смог найти ни одного полезного случая этого кода.
Может ли кто-нибудь привести полезный пример (в C ++) указателя на массив с неопределенными границами?
Или это только остаток от C?
Такой указатель не может участвовать в арифметике указателей, потенциально полезные вещи, которые еще можно сделать, это получить его тип с decltype
или же reinterpret_cast
это к другому типу указателя или intptr_t
, Это потому, что в разделе 3.9p6 говорится:
Тип класса (например, «
class X
«) может быть неполным в одном месте в единице перевода и завершаться позже; тип»class X
«является одним и тем же типом в обеих точках. Объявленный тип объекта массива может быть массивом неполного типа класса и, следовательно, неполным; если тип класса будет завершен позднее в модуле перевода, тип массива станет полным; тип массива в этих двух точках — один и тот же тип. Объявленный тип объекта массива может быть массивом неизвестного размера и поэтому может быть неполным в одной точке в единице перевода и завершаться позже; типы массива в этих двух точках («массив неизвестная границаT
«и» массивN
T
«) это разные типы. Тип указателя на массив неизвестного размера или тип, определенный объявлением typedef как массив неизвестного размера, не может быть завершен.
5.3.1 говорит:
Примечание: косвенное обращение через указатель на неполный тип (кроме
cv
void
) является действительным. Полученное таким образом l-значение может использоваться ограниченным образом (например, для инициализации ссылки); это значение не должно быть преобразовано в предварительное значение, см. 4.1.
Поскольку затухание массива в указатель может быть выполнено для значений l массива без предварительного преобразования в значение rvalue, код dyp, оставленный в комментарии, является правильным:
(*p)[i]
Соответствующее правило из 4.2:
именующий или значение типа ‘массив
N
T
» или же «массив неизвестных границT
« может быть преобразовано в значение типа «указатель наT
Msgstr «Результатом является указатель на первый элемент массива.
Я думаю, что компилятор должен принять это (независимо от параметра -O), потому что определение статического может быть предоставлено другим модулем компиляции. (Возможно, это прагматическое отклонение от стандарта — я не эксперт по С ++.) Размещенный фрагмент кода можно скомпилировать, но он неполон и не может быть приведен в исполнение без определения статического члена.
Файл c.h:
struct C {
static int v[];
};
Файл x.cpp
#include "c.h"#include <iostream>
int main(){
int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
std::cout << *((int*)p) << std::endl;
return 0;
}
Файл y.cpp
#include "c.h"int C::v[3] = {1,2,3};
Скомпилировано и скомпоновано с использованием (dont-tell-me-it-old) g ++ 4.3.3. Отпечатки 1.
И: да, я знаю, что это актерский состав.