Перейти к содержанию
    

Обращение к элементу двухмерного массива используя адрес массива

Решил сравнить адресную и индексную арифметику на приведенном выше своем примере.

Результат слегка обескуражил. Обращение к элементу массива с помощью индекса занимает меньше байтов.

Особенность системы команд ARM.

Включите оптимизацию при компиляции, результат должен стать похожим в обоих случаях. Компиляторы обычно довольно умные, что бы автоматически конвертировать индексацию в разъименование указателей и обратно, в зависимости от архитектуры и контекста применения

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Включите оптимизацию при компиляции, результат должен стать похожим в обоих случаях. Компиляторы обычно довольно умные, что бы автоматически конвертировать индексацию в разъименование указателей и обратно, в зависимости от архитектуры и контекста применения

То, что показал - лучшее. Прошелся по всем вариантам оптимизации. На мой взгляд, компилятор не должен быть настолько умным, как вы говорите. :)

Еще попробовал заменить тип переменных в массиве на uint16_t и uint32_t. В первом случае коды для адресной и индексной арифметик сравнялись, а во втором индексная арифметика опять вырвалась вперед.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В любом случае, эти два способа работают по-разному.
А вы сравните

for (int32_t j=9; j>=0; j--) GPIOA->ODR = pDig[j];

и

for (int32_t j=9; j>=0; j--) GPIOA->ODR = Digit[j];

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вы сравните...

;;;202      static const uint8_t Digit[10] = {'0','1','2','3','4','5','6','7','8','9'};
;;;203      const uint8_t *pDig = Digit;
000092  4870              LDR      r0,|L1.596|
;;;204      for (int32_t j=9; j>=0; j--) GPIOA->ODR = *(pDig++);
000094  4970              LDR      r1,|L1.600|
000096  2209              MOVS     r2,#9
                  |L1.152|
000098  f8103b01          LDRB     r3,[r0],#1
00009c  f8c1380c          STR      r3,[r1,#0x80c]
0000a0  1e52              SUBS     r2,r2,#1
0000a2  d5f9              BPL      |L1.152|
0000a4  4a6b              LDR      r2,|L1.596|
;;;205      for (int32_t j=9; j>=0; j--) GPIOA->ODR = Digit[j]; 
0000a6  2009              MOVS     r0,#9
                  |L1.168|
0000a8  5c13              LDRB     r3,[r2,r0]
0000aa  f8c1380c          STR      r3,[r1,#0x80c]
0000ae  1e40              SUBS     r0,r0,#1
0000b0  d5fa              BPL      |L1.168|

Это ничего не меняет. Отличия именно в адресации элементов массива.

Похоже, разработчики ARM специально "подрихтовали" процессор под C.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Результат слегка обескуражил. Обращение к элементу массива с помощью индекса занимает меньше байтов.

Особенность системы команд ARM.

Не надо все системы команд ARM-ов обобщать. Это система кортекса-М3. Для ARM v4 32 бита одинаковое кол-во слов, команд и тактов.

А во-вторых, алгоритмы в примерах разные. В первом инкремент указателя, во втором взятие элементов с конца массива.

В-третьих нафига козе баян в виде скобок *(pDig++) ?

Попробуйте без них *pDig++

 

В случает ТС разница между *** и **[] будет катастрофическая

Что такое ТС? "В случает ТС"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не надо все системы команд ARM-ов обобщать. Это система кортекса-М3. Для ARM v4 32 бита одинаковое кол-во слов, команд и тактов.

А во-вторых, алгоритмы в примерах разные. В первом инкремент указателя, во втором взятие элементов с конца массива.

В-третьих нафига козе баян в виде скобок *(pDig++) ?

Попробуйте без них *pDig++

Насчет скобок - согласен, можно без них. Просто тяжелее воспринимать. Убрал. В книжках их, кстати, пишут. По той же причине.

Насчет взятия элементов с конца массива - упустил из виду. Не сомневаюсь, что результат не изменится. Зря не сомневался :) Начинать-то нужно с нуля, потом инкрементировать счетчик и сравнивать с 10. Стало на 2 байта больше.

А система команд - Thumb-2 называется. Виноват. Имел в виду систему команд от фирмы ARM. Опять же, это чисто качественный пример. Для ARMv4 команды для двух арифметик тоже будут разные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже, разработчики ARM специально "подрихтовали" процессор под C.
Все с точностью до наоборот... :)

Большая часть кода С(когда-то написанного) используют адресную арифметику т.к. на

большинстве процессоров/компиляторов это дает выигрыш.

А Ваш пример действительно интересен, надо будет не забыть поиграться с этим

при переносе проекта на кортекс.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это ничего не меняет. Отличия именно в адресации элементов массива.
Да что ж вы сравниваете два алгоритма и удивляетесь разнице? Еще раз говорю, сравните в одинаковом цикле обращение pDig[j] и Digit[j], сравните *(pDig + j) и *(Digit + j), а потом посмотрите на оба варианта исходного текста

 

(int32_t j=9; j>=0; j--) GPIOA->ODR = *(pDig + j);
и
(int32_t j=9; j>=0; j--) GPIOA->ODR = *(Digit + j);

или

(int32_t j=9; j>=0; j--) GPIOA->ODR = pDig[j];
и
(int32_t j=9; j>=0; j--) GPIOA->ODR = Digit[j];

и подумайте: не видя объявления pDig и Digit вы только глядя на их использование сможете сказать, который из них массив, а который указатель? Нет, не сможете. Вот это я и пытаюсь объяснить на протяжении двух страниц.

 

 

В случает ТС разница между *** и **[] будет катастрофическая
Не верю. Покажите ее. Аргументируйте утверждение. С указателем получается так:
#define PROFILE                ((sub_profile ***)(0x0801F000))

void test()
{
    unsigned int volatile temp;
    temp = PROFILE[1][0]->type;
}

166 0000 18309FE5         ldr    r3, .L7    @ tmp137,
167 0004 043093E5         ldr    r3, [r3, #4]    @ tmp138,
168 0008 003093E5         ldr    r3, [r3, #0]    @ tmp139,
169 000c B030D3E1         ldrh    r3, [r3, #0]    @ temp.29, D.3609_3->type

186                  .L7:
187 0020 00F00108         .word    134344704

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не верю. Покажите ее.
Посыпаю голову пеплом - разницы действительно нет (за исключением того, что конструкция **[] отказывается компилится). Разница проявляется в другом контексте

 

 

2 GetSmart: ТС - это 'Топик Стартер'

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да что ж вы сравниваете два алгоритма и удивляетесь разнице? Еще раз говорю, сравните в одинаковом цикле обращение pDig[j] и Digit[j], сравните *(pDig + j) и *(Digit + j... не видя объявления pDig и Digit вы только глядя на их использование сможете сказать, который из них массив, а который указатель? Нет, не сможете. Вот это я и пытаюсь объяснить на протяжении двух страниц.

Так я ж не спорю о том, что Digit[j] и *(Digit + j) - это одно и то же. Наоборот, подтверждал. :) А удивляюсь я тому, что известное правило отказываться от индексной арифметики в пользу адресной для ARM не работает. Может быть, для многомерных массивов все "вернется на круги своя"...

 

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

Должна компилироваться!:) Скорее всего, что-то не так определено.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Должна компилироваться!:) Скорее всего, что-то не так определено.

Не должно:

t.cc: In function 'void test()':

t.cc:10:12: error: ISO C++ forbids casting to an array type 'sub_profile** []'

Для С аналогично (текст сообщения об ошибке немного другой, но смысл тот же)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не должно:

Такое годится? Трудно понять, но, кажется, делает, что задумано. Ни ошибок, ни предупреждений.

  static const uint8_t a = 'A', b = 'B', c = 'C', d = 'D';
  static const uint8_t *pa = &a, *pb = &b, *pc = &c, *pd = &d;
  static const uint8_t **ptr[] = {&pa, &pb, &pc, &pd};
  for (int32_t i=0; i<4; i++) GPIOA->ODR = **ptr[i];

Результат компиляции:

;;;210      static const uint8_t a = 'A', b = 'B', c = 'C', d = 'D';
;;;211      static const uint8_t *pa = &a, *pb = &b, *pc = &c, *pd = &d;
;;;212      static const uint8_t **ptr[] = {&pa, &pb, &pc, &pd};
;;;213      for (int32_t i=0; i<4; i++) GPIOA->ODR = **ptr[i];
0000b4  4965              LDR      r1,|L1.588|
0000b6  2000              MOVS     r0,#0
0000b8  3120              ADDS     r1,r1,#0x20
                  |L1.186|
0000ba  f8513020          LDR      r3,[r1,r0,LSL #2]
0000be  681b              LDR      r3,[r3,#0]
0000c0  781b              LDRB     r3,[r3,#0]
0000c2  f8c2380c          STR      r3,[r2,#0x80c]
0000c6  1c40              ADDS     r0,r0,#1
0000c8  2804              CMP      r0,#4
0000ca  dbf6              BLT      |L1.186|

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ага, только эти a b c тоже как-бээ массивы указателей должны быть ) у ТС профиль - это массив указателей на подпрофили, а дефайн этот указывает на массив профилей...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В тему указатели-массивы (накидал примерчик за 5 минут):

uint8_t* get_first_middle_of_tripple(uint8_t* p, size_t qty)
{
   if (qty>=3)
   {   
      while (qty--)
      {
         p++;

         if ((p[0] == p[-1]) && (p[0] == p[1]))
         {
            return (p);
         }
      }
   }
   return (NULL);
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...