Страница 1 из 1

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

Добавлено: Ср июн 22, 2022 21:47:47
maksimdag0
Все добрый вечер!
Я столкнулся с таким случаем: передаю массив в функцию test, через указатель (см. фото 1). В теле этой функции я передаю массив другой функции - big, но передаю по одному элементу таким образом - каждый элемент массива преравниваю к первому элементу и передаю его в функцию big, НО это не работает, почему? Почему нельзя записать в первый элемент массива его любой другой элемент? (см. фото 2)
Я отслеживал под отладкой это процесс, и выявил что никакое значение не записывается в первый элемент массива, и даже больше значение arr не изменялось вообще, хотя переменная "i" изменялась. подскажите пожалуйста, что я не знаю, почему так происходит?

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

Добавлено: Ср июн 22, 2022 22:29:25
korsaj
Ну так передайте указатель. А еще лучше почитайте про указатели.

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

Добавлено: Ср июн 22, 2022 22:37:11
VladislavS
Как объявлен arr предлагается угадать?

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

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

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

Добавлено: Чт июн 23, 2022 06:46:25
a797945
отключите оптимизацию
компилятор, скорее всего, просто вас не понял

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

Добавлено: Чт июн 23, 2022 07:45:21
maksimdag0
korsaj писал(а):Ну так передайте указатель. А еще лучше почитайте про указатели.
Я ошибся там не "arr", а arr_2

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

Добавлено: Чт июн 23, 2022 09:22:00
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 10:40:51
maksimdag0
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
a797945
что сложно?
речь, почему можете не увидеть Ваш код на выходе компиляции.
примерьте ситуацию на себя - Вы будете перетаскивать кирпичи с места на место, если в этом нет ну совершенно никакой потребности?
если цепочка команд не приводит каким-либо практическим результатам - эта цепочка компилятором может быть "забыта". применительно к Вашему массиву - если содержание массива Вы в дальнейшем никак не используете и компилятор это "просматривает" - ну и зачем ему что-то конфигурить для сущности у которой не будет никакого применения: ни применена в дальнейших расчетах, ни выведена "наружу", ни передана в периферию ...
Хотите увидеть абстрактно как может быть скомпилирован Ваш код, отключите оптимизацию - будет оттранслирован "как есть", без учета "а что собственно нужно" и "как это оптимальнее сделать".

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