C - что такое имя массива, когда не преобразован в указатель его типа? - PullRequest
2 голосов
/ 06 апреля 2019

Так что какое-то время я путался с именами массивов и указателями.

Мы заявляем int a[10]; И где-то в будущем также есть a и &a.

Итак, я понял, как работает синтаксис. a - имя массива. Когда он не используется в качестве операнда для sizeof & и т. Д., Он будет преобразован или "распаден", поэтому он возвращает указатель на целое число, содержащее адрес первого элемента массива.

Если имя массива используется в качестве операнда для sizeof или &, его тип равен int (*)[10]. Поэтому я думаю, что тип отличается, потому что этот "распад" не происходит.

Но я до сих пор не понимаю, как работает &a. Насколько я понимаю, он дает мне адрес whatever it was before the "decay" happened .. Итак, до того, как произойдет «затухание» указателя, что это такое и как компилятор работает с «оригиналом» для оценки &a?

Для сравнения, если мы объявим int *p; и позже есть &p и p где-то в коде ...

В этом случае указателю на целое число p присваивается отдельная ячейка указателя со своим адресом, и значением по этому адресу будет любой адрес, который мы ему присвоим (или значение мусора при этом предварительном назначении адреса).

a не получает отдельной ячейки указателя в памяти, когда она объявлена ​​int a[10]. Я слышал, это идентифицируется со смещением в регистре %ebp. Тогда что происходит с компилятором, когда он оценивает &a? «Распад» на указатель на целое число не происходит, во-первых, отдельного «указателя» не было. Тогда что компилятор идентифицирует a как и что он делает, когда видит, что унарный оператор & использует имя массива в качестве операнда?

Ответы [ 3 ]

3 голосов
/ 06 апреля 2019

Дано:

int a[10];

объект a имеет тип int[10]. Выражение a в большинстве, но не во всех контекстах "распадается" на выражение указателя; выражение дает значение типа int*, эквивалентное &a[0].

Но я до сих пор не понимаю, как работает &a. Насколько я понимаю, он дает мне адрес , какой он был до того, как произошел "распад" .. Итак, до того как произошел "распад" на указатель, что это такое и как компилятор работает с «оригинал» для оценки &a?

Это не совсем правильно. В &a распад вообще не происходит. a имеет тип «массив 10 int» (int[10]), поэтому &a имеет тип «указатель на массив 10 int» (int(*)[10]).

В этом нет ничего особенного. Для любого имени foo типа some_type выражение &foo имеет тип "указатель на some_type". (Что смущает, так это то, что это один из редких случаев, когда имя массива не ведет себя странно.)

Лучше всего думать о словах «массив» и «указатель» как о прилагательных, а не как существительные. Таким образом, мы можем иметь объект массива, выражение массива, тип массива и т. Д., Но просто «массив» является неоднозначным.

Это:

int a[10];

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

1 голос
/ 06 апреля 2019

Тогда что компилятор определяет как и что он делает, когда видит, что унарный оператор & использует имя массива в качестве операнда?

Компилятор идентифицирует aв виде 10-элементного целочисленного массива, и когда он видит оператор &, он возвращает адрес этого массива.

Так же, как он будет видеть int i = 3; как целое число, а &i какадрес этого целого числа.

0 голосов
/ 06 апреля 2019

Относительно получения адреса массива: массив является объектом сам по себе, поэтому он имеет как размер, так и адрес (хотя брать его адрес редко полезно).

ПреобразованиеМассив на указатель на его первый элемент является формой приведения типов.Это происходит только в том случае, если альтернативой будет ошибка компиляции.

Например, вы не можете сравнить массив с указателем, поэтому массив (неявно) приводится (приведен) к int* (дляего первый элемент), а затем сравниваются типы указателей.В Си вы можете сравнить любые типы указателей.C просто не волнует (хотя, скорее всего, он выдаст предупреждение).

На самом деле это сравнение int* с int(*)[10] в отношении типов, как вы сказали.Они должны иметь один и тот же адрес (независимо от ввода), поскольку массивы хранят свои данные напрямую.Таким образом, адрес массива всегда будет адресом его первого элемента.

Однако получить размер массива не является ошибкой, поэтому sizeof(a) получает размер всего массива, так как нетпринуждение необходимо, чтобы сделать это законным.Так что это то же самое, что и sizeof(int[10]).

Ваш другой случай sizeof(&a) действительно sizeof(int(*)[10]), как вы сказали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...