В C/С++ для массива a я только что узнал, что (void *) & a == (void *) a. Как это работает? - программирование
Подтвердить что ты не робот

В C/С++ для массива a я только что узнал, что (void *) & a == (void *) a. Как это работает?

Итак, я всегда знал, что массив "объектов", которые передаются в C/С++, просто содержит адрес первого объекта в массиве.

Как указатель на массив "объект" и он содержит значение, то же самое?

Может ли кто-нибудь указать мне на дополнительную информацию, возможно, на то, как все, что работает в сборке, возможно.

4b9b3361

Ответ 1

Короткий ответ: указатель на массив определяется таким же значением, как указатель на первый элемент массива. То, как работают массивы на C и С++.

Педантичный ответ:

C и С++ имеют выражения rvalue и lvalue. Lvalue - это то, к чему может применяться оператор &. Они также имеют неявные преобразования. Перед использованием объект может быть преобразован в другой тип. (Например, если вы вызываете sqrt( 9 ), то 9 преобразуется в double, потому что sqrt( int ) не определен.)

lvalue типа массива неявно преобразуется в указатель. Неявное преобразование изменяет array на &array[0]. Это также может быть явно выписано как static_cast< int * >( array ) в С++.

Делать это нормально. Кастинг до void* - это еще одна история. void* немного уродлив. И кастинг с круглыми скобками как (void*)array также уродлив. Поэтому, пожалуйста, избегайте (void*) a в фактическом коде.

Ответ 2

Вы смешиваете две несвязанные (и, фактически, взаимоисключающие) вещи, что создает больше путаницы.

Во-первых, вы правильно заявляете, что "объекты массива, которые передаются в C/С++, просто содержат адрес первого объекта в массиве". Ключевые слова здесь "пройдены". В действительности массивы не могут быть переданы как объекты массива. Массивы не копируются. Всякий раз, когда вы используете объявление типа массива в списке параметров функции, оно фактически интерпретируется как объявление указателя, то есть это указатель, который вы "проходите", а не массив. Однако в таких ситуациях ваше равенство не выполняется

void foo(int a[]) {
  assert((void *) &a == (void *) a); // FAIL!!!
}

Вышеприведенное утверждение гарантированно терпит неудачу - равенство не выполняется. Итак, в контексте этого вопроса вы должны забыть о массивах, которые вы "проходите" (по крайней мере, для синтаксиса, используемого в приведенном выше примере). Ваше равенство не выполняется для массивов, которые были заменены объектами-указателями.

Во-вторых, реальные объекты массива не являются указателями. И нет необходимости использовать термин "объект" в кавычках. Массивы - это полноценные объекты, хотя и с некоторыми своеобразными свойствами. Соответствующее равенство действительно выполняется для реальных массивов, которые не потеряли свою "массивность", т.е. Объект массива, который не был заменен объектами-указателями. Например

int a[10];
assert((void *) &a == (void *) a); // Never fails

Что это значит, так это то, что численный адрес всего массива совпадает с адресом его первого элемента. Здесь ничего необычного. Фактически, то же самое (в природе) равенство можно наблюдать с помощью типов структур в C/С++

struct S { int x; } a;
assert((void *) &a == (void *) &a.x); // Never fails

т.е. адрес всего структурного объекта совпадает с адресом его первого поля.

Ответ 3

Как указатель на массив "объект" и он содержит значение, то же самое?

Массив - это непрерывный блок памяти, в котором хранится несколько элементов. Очевидно, что первый элемент в массиве находится на каком-то адресе. Нет данных "между" первым элементом и началом фактического массива.
Следовательно, первый элемент имеет тот же адрес, что и массив.

Ответ 4

Прочитайте следующий поток

http://www.cplusplus.com/forum/beginner/29595/

В основном объясняется, что (&a != a) из-за разницы в типе (поскольку &a возвращает указатель на массив и a на первый элемент), хотя оба они указывают на один и тот же адрес.

Поскольку вы отбрасываете их на (void*), сравнивается только значение адреса и считается равным, что означает ((void*) a == (void*)&a), как вы сказали. Это имеет смысл, поскольку адрес массива должен быть таким же, как и первые элементы.

Ответ 5

Посмотрим на эти два объявления:

int a[4];
int * b;

Оба a и b имеют тип, совместимый с int * и могут, например, передаваться в качестве аргумента функции, ожидающей int *:

void f(int * p);
f(a); // OK
f(b); // OK

В случае a компилятор выделяет пространство для 4 значений int. Когда вы используете имя a, например, при вызове f(a), компилятор просто заменяет адрес того, где он выделил первое из этих значений int, поскольку он знает.

В случае b компилятор выделяет пространство для одного указателя. Когда вы используете имя b, например, при вызове f(b), компилятор генерирует код для извлечения значения указателя из выделенного хранилища.

Когда дело доходит до &, это становится очевидным, когда разница между a и b становится очевидной. & всегда означает адрес хранилища, который компилятор выделил для вашей переменной: &a - это адрес этих четырех значений int (поэтому совпадает с просто a), а &b - это адрес значения указателя, У них тоже разные типы.

&a не совсем то же самое, что и a, хотя они сравниваются как равные. Они имеют другой тип: &a - это указатель, а a - массив. Вы можете заметить разницу, например, если вы примените оператор sizeof к этим выражениям: sizeof(a) будет оценивать размер четырех значений int, а sizeof(&a) - размер указателя.

Ответ 6

Хорошо, так что я думал, что когда вы создали массив, вы выделили место для массива где-то, и вы создали указатель на его первый объект где-то еще, и то, что вы передали в своем коде, было указателем.

На самом деле это поведение того, что происходит, когда вы создаете массив с новым в С++ или с malloc в C/С++. Таким образом,

int * a = new a[SIZE];
assert((void*)&a==(void*)a); // Always fails

Что я узнал, так это то, что для массивов, объявленных в стиле int a[SIZE];, при попытке передать массив функции (это называется распадом-указателем-матрицей) создается указатель на первый элемент. Интересно отметить, что, как пишет AndreyT,

void foo(int a[]) {
     assert((void *) &a == (void *) a); // Always fails
}

Это показывает, что только при попытке передать массивы вокруг этого указателя создается для массивов в стиле int a[SIZE];.