maksimdag0, вам надо переосмыслить как компилятор "видит" код, который вы пишете. Для него важны только volatile сущности, со всем остальным он может обходиться как хочет. Вот взять, например, компилятор IAR и ваш код с пустой функцией big(). Смотрите что получится
Код: Выделить всё
void big(int x) { }
void test (int *arr_2)
{
for(int i=0; i<3; i++)
{
arr_2[0]=arr_2[i];
big(arr_2[0]);
LDR R1,[R0, #+4] // R1 = arr_2[1]
STR R1,[R0, #+0] // arr_2[0] = R1
LDR R2,[R0, #+8] // R1 = arr_2[2]
STR R2,[R0, #+0] // arr_2[0] = R1
}
}
BX LR
Компилятор посчитал, что это всё что делает программа. Никаких циклов и передачи параметров в функцию нет.
Теперь введём в функцию big() volatile сущность.
Код: Выделить всё
void big(int x) { GPIOA->IDR=x; }
void test (int *arr_2)
{
for(int i=0; i<3; i++)
LDR.N R1,??DataTable2 // R1 = &GPIOA->IDR
{
arr_2[0]=arr_2[i];
big(arr_2[0]);
LDR R2,[R0, #+0] // R2 = arr_2[0]
STR R2,[R1, #+0] // GPIOA->IDR = R2
LDR R2,[R0, #+4] // R2 = arr_2[1]
STR R2,[R0, #+0] // arr_2[0] = R2
STR R2,[R1, #+0] // GPIOA->IDR = R2
LDR R2,[R0, #+8] // R2 = arr_2[2]
STR R2,[R0, #+0] // arr_2[0] = R2
STR R2,[R1, #+0] // GPIOA->IDR = R2
}
}
BX LR
Мы можем видеть, что добавилось полезное действие - последовательный вывод в GPIOA->IDR элементов массива.
Но это ещё не всё. Немного поможем компилятору, избавим его от глупого кода.
Код: Выделить всё
void big(int x) { GPIOA->IDR=x; }
void test (int *arr_2)
{
for(int i=0; i<3; i++) big(arr_2[i]);
LDR.N R1,??DataTable2 // R1 = &GPIOA->IDR
LDR R2,[R0, #+0] // R2 = arr_2[0]
STR R2,[R1, #+0] // GPIOA->IDR = R2
LDR R2,[R0, #+4] // R2 = arr_1[1]
STR R2,[R1, #+0] // GPIOA->IDR = R2
LDR R2,[R0, #+8] // arr_1[0] = R2
STR R2,[R1, #+0] // GPIOA->IDR = R2
}
BX LR
Лучше, нет лишних действий, но всё равно что-то не то. Потому что компилятор пока что не знает что мы ему в функцию передаём, это просто листинг тела функции.
Попробуем эту функцию вызвать c константными данными.
Код: Выделить всё
void big(int x) { GPIOA->IDR=x; }
const int arr_1[3] = { 1,2,3 };
int main()
{
test((int *)arr_1);
LDR.N R0,??DataTable2 // R0 = &GPIOA->IDR
MOVS R1,#+1
STR R1,[R0, #+0] // GPIOA->IDR = 1;
MOVS R2,#+2
STR R2,[R0, #+0] // GPIOA->IDR = 2;
MOVS R3,#+3
STR R3,[R0, #+0] // GPIOA->IDR = 3;
}
Ровно то что и задумано, в GPIOA->IDR последовательно записано 1,2,3 без всяких массивов и циклов вообще. Потому что GPIOA->IDR это volatile сущность и только она в этой программе важна для компилятора. Ну и для программиста, конечно, тоже, если он хочет писать привильные программы. Смотрите, что будет, если big() не будет воздействовать на volatile сущности.
Код: Выделить всё
void big(int x) { }
const int arr_1[3] = { 1,2,3 };
void test (int *arr_2)
{
for(int i=0; i<3; i++) big(arr_2[i]);
}
int main()
{
test((int *)arr_1);
for(;;);
??main_0:
B.N ??main_0
}
Всё "почикано" под корень. Вот, это вам пища для размышлений. С опытом должно прийти понимание того что же на самом деле делает написанный вами код. Это основы языка программирования, которым почему-то нигде не учат.
PS: Это я ещё взял компилятор, который бережно работает с доступом по указателю. GCC бы всё это "вычистил под ноль" ещё на первом шаге.