Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Вопрос по массиву

Ср июн 22, 2022 21:47:47

Все добрый вечер!
Я столкнулся с таким случаем: передаю массив в функцию test, через указатель (см. фото 1). В теле этой функции я передаю массив другой функции - big, но передаю по одному элементу таким образом - каждый элемент массива преравниваю к первому элементу и передаю его в функцию big, НО это не работает, почему? Почему нельзя записать в первый элемент массива его любой другой элемент? (см. фото 2)
Я отслеживал под отладкой это процесс, и выявил что никакое значение не записывается в первый элемент массива, и даже больше значение arr[i] не изменялось вообще, хотя переменная "i" изменялась. подскажите пожалуйста, что я не знаю, почему так происходит?
Вложения
Screenshot_2.png
(3.07 KiB) Скачиваний: 96
Screenshot_1.png
(1.44 KiB) Скачиваний: 74

Re: Вопрос по массиву

Ср июн 22, 2022 22:29:25

Ну так передайте указатель. А еще лучше почитайте про указатели.

Re: Вопрос по массиву

Ср июн 22, 2022 22:37:11

Как объявлен arr предлагается угадать?

Re: Вопрос по массиву

Чт июн 23, 2022 05:45:36

Там у вас всё чето сильно позапутано всё, неясна конечная цель и что для чего делается. Если нулевому элементу входного массива присваивается значение из неизвестно откуда взявшегося массива, а потом этот элемент передается в другую функцию, то можно всю эту цепочку сократить, убрав лишние действия:

Re: Вопрос по массиву

Чт июн 23, 2022 06:46:25

отключите оптимизацию
компилятор, скорее всего, просто вас не понял

Re: Вопрос по массиву

Чт июн 23, 2022 07:45:21

korsaj писал(а):Ну так передайте указатель. А еще лучше почитайте про указатели.
Я ошибся там не "arr", а arr_2[i]

Re: Вопрос по массиву

Чт июн 23, 2022 09:22:00

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 бы всё это "вычистил под ноль" ещё на первом шаге.

Re: Вопрос по массиву

Сб июн 25, 2022 10:40:51

VladislavS писал(а):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 бы всё это "вычистил под ноль" ещё на первом шаге.
Большое спасибо, буду разбираться, пока сложно это понять)

Re: Вопрос по массиву

Сб июн 25, 2022 21:34:22

что сложно?
речь, почему можете не увидеть Ваш код на выходе компиляции.
примерьте ситуацию на себя - Вы будете перетаскивать кирпичи с места на место, если в этом нет ну совершенно никакой потребности?
если цепочка команд не приводит каким-либо практическим результатам - эта цепочка компилятором может быть "забыта". применительно к Вашему массиву - если содержание массива Вы в дальнейшем никак не используете и компилятор это "просматривает" - ну и зачем ему что-то конфигурить для сущности у которой не будет никакого применения: ни применена в дальнейших расчетах, ни выведена "наружу", ни передана в периферию ...
Хотите увидеть абстрактно как может быть скомпилирован Ваш код, отключите оптимизацию - будет оттранслирован "как есть", без учета "а что собственно нужно" и "как это оптимальнее сделать".

в двух стилях вам рассказали :)
Владислав профессионально и наглядно.
ну и вот, типа на пальцах
Ответить