Обратимся к языковой стороне, поскольку ассемблерная сторона уже обработана:
Обратите внимание на это предложение: «выражение в форме a [i] заставляет массив распадаться на указатель, следуя приведенному выше правилу, а затем подписываться так же, как переменная указателя в выражении p [i] (хотя возможный доступ к памяти будет другим, «я довольно запутался в этом: поскольку a распался на указатель, то почему он имеет в виду« доступ к памяти будет другим? »
Это потому, что после затухания, доступ равен (теперь значение указателя) и указателю. Но разница в как в том, что значение указателя получается в первую очередь. Давайте посмотрим на пример:
char c[1];
char cc;
char *pc = &cc;
Теперь у вас есть массив. Этот массив не занимает хранения, кроме одного символа! для него не сохранен указатель . И у вас есть указатель, который указывает на символ. Указатель принимает размер одного адреса, и у вас есть один символ, на который указывает указатель. Теперь давайте посмотрим, что происходит в случае массива, чтобы получить значение указателя:
c[0] = 'A';
// #1: equivalent: *(c + 0) = 'A';
// #2: => 'c' appears not in address-of or sizeof
// #3: => get address of "c": This is the pointer value P1
Случай с указателем другой:
pc[0] = 'A';
// #1: equivalent: *(pc + 0) = 'A';
// #2: => pointer value is stored in 'pc'
// #3: => thus: read address stored in 'pc': This is the pointer value P1
Как вы видите, для случая массива для получения значения указателя, где мы добавляем значение индекса (в данном случае скучно 0
), нам не нужно читать из памяти, потому что адрес массив уже является необходимым значением указателя. Но для случая с указателем нужное нам значение указателя хранится в указателе: нам нужно одно чтение из памяти, чтобы получить этот адрес.
После этого путь для обоих равен:
// #4: add "0 * sizeof(char)" to P1. This is the address P2
// #5: store 'A' to address P2
Вот код ассемблера, сгенерированный для массива и регистр указателя:
add $2, $0, 65 ; write 65 into r2
stb $2, $0, c ; store r2 into address of c
# pointer case follows
ldw $3, $0, pc ; load value stored in pc into r3
add $2, $0, 65 ; write 65 into r2
stb $2, $3, 0 ; store r2 into address loaded to r3
Мы можем просто сохранить 65
(ASCII для 'A'
) по адресу c
(который будет известен уже во время компиляции или соединения, когда он глобален). В случае указателя нам сначала нужно будет загрузить сохраненный им адрес в регистр 3
, а затем записать 65
по этому адресу.