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

Формирование int из массива char

К чему в очередной раз поминание древней глупости - "преждевременная оптимизация" ?

http://electronix.ru/forum/index.php?showt...t&p=1348755

Нет времени отвечать на ваши глупости. Кто имеет уши - тот услышит.

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


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

И это тоже. Прогресс в компиляторостроении привёл к тому, что вот эти стенания "а как же эти лишние две инструкции?" - зачастую устаревшая выдумка

Типичный аргумент кодера-форточника, создающего шедевры, способные показом обычного диалога загрузить intel-i7 на 100% на минуту.

Но даже не так, пара лишних тактов и байтов вредит крайне редко. Короче, "преждевременная оптимизация", если говорить без матюков, но иметь в виду именно их :smile3009:

Предположим: нужна функция, инкрементирующая пакованный int. С __packed на Cortex-M это будет:

LDR R1, [R0]
ADDS R1, R1, #1
STR R1, [R0]
BX LR

В случае с memcpy будет: создание стекового фрейма, копирование, инкремент, опять копирование, удаление стекового фрейма - итого:

не на пару байт, а во много раз (!!!) дольше + занимает доп.регистры + доп.стек.

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


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

Предположим: нужна функция, инкрементирующая пакованный int. С __packed на Cortex-M это будет:

LDR R1, [R0]
ADDS R1, R1, #1
STR R1, [R0]
BX LR

Попробовал на своём Cortex-M0. Не работает :crying:

 

В случае с memcpy будет: создание стекового фрейма, копирование, инкремент, опять копирование, удаление стекового фрейма - итого:

не на пару байт, а во много раз (!!!) дольше + занимает доп.регистры + доп.стек.

Глупость какая. Только что попробовал на Cortex-M3: как и положено, вместо memcpy подставляет LDR/STR.

 

А по мне так наоборот - если происходит действие "обращение по указателю" - то логично было бы использовать предусмотренные для этого в языке средства разыменования указателя, а не захламлять исходник вызовами memcpy(). То, что этот указатель учитывает какие-то аппаратные особенности (невыровненный доступ), логично было бы как-то указать один раз при объявлении указателя (тот же __packed), а не распылять по исходнику в виде memcpy() и надеяться, что программист не забудет именно этот указатель использовать через memcpy().

 

В gcc можно обернуть искомые данные в упакованную структуру и обращаться по указателю на эту структуру.

Наверное, всё дело в том, что мне не доводилось писать код с невыровненным доступом, потому и удивляюсь. А ради одного-двух случаев в коде я точно не стал бы городить packed, а сделал бы memcpy. Хотя могу представить себе такой код - lwip, к примеру. Там нужно постоянно обращаться к полям пакетов, и там повсеместно используются упакованные структуры. Альтернатива - сделать функции доступа к полям через указание смещений, но это точно будет выглядеть коряво на фоне упакованных структур, так что принято.

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


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

Наверное, всё дело в том, что мне не доводилось писать код с невыровненным доступом, потому и удивляюсь.

Практически абсолютно любой протокол обмена требует обращения ко всяким разным полям (в том числе и битовым )во фрейме, то что они не выровнееные это практически наверняка и если не писать разбоку и формирование в стиле "третий бит в пятом байте слева" (за что вообще-то надо сразу чего нибудь оторвать, что болтается), то сразу становятся необходимыми структуры и обьединения. Причем, если платформа не восьмибитовая, то сразу возникают понятия раковки стуктур и на многих платформах невыровненный доступ. Но проблема доступа в таком случае сразу скрывает компилятор.

Но в общем структуры организуются СОВЕРШЕННО не для того, что-бы бороться с выравниваним и заявление:

А ради одного-двух случаев в коде я точно не стал бы городить packed

более чем....

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


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

typedef volatile uint32_t REG32;
#define pREG32 (REG32 *)
#define USB_TXDATA                                (*(pREG32 (0x4002001C)))

uint8_t *pData;

USB_TXDATA = *((uint32_t __attribute__((packed)) *)pData);

В тех примерах от NXP которые у меня:

#if defined(__GNUC__)   // Code Red tools

...

// The following two typedefs are required as GCC does
// not directly support a method of hinting that a variable
// (as opposed to a structure) should be accessed with
// the assumption that it is unaligned, which can be done
// in Keil using, for example, __packed uint32_t *p;
typedef struct { uint32_t value __attribute__(( packed ));
}unaligned_uint32;

typedef struct { uint16_t value __attribute__(( packed ));
}unaligned_uint16;

...

А использование что-то вроде такого:

#if defined(__GNUC__)
          (( unaligned_uint16 *)EP0Buf)->value = (USB_EndPointHalt & m) ? 1 : 0;;
#else
          *((__packed uint16_t *)EP0Buf) = (USB_EndPointHalt & m) ? 1 : 0;
#endif

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


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

А использование что-то вроде такого:

#if defined(__GNUC__)
          (( unaligned_uint16 *)EP0Buf)->value = (USB_EndPointHalt & m) ? 1 : 0;;
#else
          *((__packed uint16_t *)EP0Buf) = (USB_EndPointHalt & m) ? 1 : 0;
#endif

Интересно, зачем так? Ведь гнусишный вариант вполне может работать и с RealView.

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


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

Интересно, зачем так? Ведь гнусишный вариант вполне может работать и с RealView.

Там были глупостей и ошибки похлеще, но работало. Подозреваю что вначале написали на Кейле, а потом другой человек отпортировали на gcc не слишком задумываясь, лишь бы работало.

Изменено пользователем Kabdim

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


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

В случае с memcpy будет: создание стекового фрейма...
Такого ужаса уже давно нет.

По крайней мере, в gcc практически все библиотечные функции за'builtin'ены, и компилятор встраивает и разворачивает их максимально гибко, вплоть до того, что sin(const) и иже с ним считается чуть-ли не на этапе препроцессинга и может использоваться даже для инициализации констант.

 

          typedef struct { uint16_t value __attribute__(( packed ));}unaligned_uint16_t;

          (( unaligned_uint16_t *)EP0Buf)->value = 1;

С выкрутасом решение, но читаемость хромает.

Если запрятать это в макрос, то читаемость поднимется в разы...

Спасибо! Может когда-нибудь пригодится.

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


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

Такого ужаса уже давно нет.

По крайней мере, в gcc практически все библиотечные функции за'builtin'ены, и компилятор встраивает и разворачивает их максимально гибко, вплоть до того, что sin(const) и иже с ним считается чуть-ли не на этапе препроцессинга и может использоваться даже для инициализации констант.

Часто приходится компилить без оптимизации, для отладки и т.п. С отключенной оптимизацией разве развернёт?

Один фиг - писать все эти memcpy() для доступа к одной пакованной переменной - это как раз глупо и слишком громоздко (снижает читаемость исходника).

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


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

Часто приходится компилить без оптимизации, для отладки и т.п. С отключенной оптимизацией разве развернёт?
Не знаю, т.к. меня этот вопрос вообще не заботит.

 

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


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

Задача такая - есть массив test_buff, из подряд идущих 4-х элементов которого нужно сформировать переменную unsigned int.

 

unsigned char test_buff[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};

unsigned char *tst_point = &test_buff[0];

unsigned int *tst;

 

tst = (unsigned int *)(tst_point + 2*sizeof(unsigned char)); //должны получить 0x06050403 = 100992003

 

Т.е. в *tst пытаюсь записать unsigned int, состоящий из байтов массива с 3-го по 6-й.

 

При исполнении этого кода на ARM-процессоре (ядро Cortex-M1) происходит зависание ядра (когда обращаюсь к адресу, некратному 4 байтам).

При исполнении этого же кода на ПК - все ок, *tst = 100992003, как и должно быть.

Компилятор Keil.

 

Есть идеи, как решить задачу?

 

А ваш процессор Big endian или little endian? Вроде в АРМ это переключить можно, хотя чаще всего он он little endian.

Второй вопрос в вашем массиве данные Big endian или little endian?

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


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

Один фиг - писать все эти memcpy() для доступа к одной пакованной переменной - это как раз глупо и слишком громоздко (снижает читаемость исходника).

ради одной пакованной переменной писать кучу #if при объявлении, с различными прагмами/атрибутами для разных компиляторов не менее глупо.

лучше уж макрос или инлайн функция которая возвращает нормальный int из невыровненного адреса.

 

в единственном случае где могут понадобится упакованные структуры и где без этого вполне можно обойтись - в случае с протоколами обмена, там всё равно все доступы к структуре будут обёрнуты в hton / ntoh. ну будет еще одна обёртка для выравнивания, тоже мне проблема.

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


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

ради одной пакованной переменной писать кучу #if при объявлении, с различными прагмами/атрибутами для разных компиляторов не менее глупо.

лучше уж макрос или инлайн функция которая возвращает нормальный int из невыровненного адреса.

Городить какую-то функцию, которая будет разбитаться как именно невыровнен адрес а может и выровнен.... тода уж memcpy() - эта занимается тем-же самым, но понятно, что делает.

И все это ради того, что-бы отвергать великолепный механизм паковки и доступа к структурам. Дурдом. Но понятный после этого заявления:

в единственном случае где могут понадобится упакованные структуры и где без этого вполне можно обойтись - в случае с протоколами обмена

становится понятным, что задачи обмена данными бесконечно далеки от Вас и "контроллеров светодиодов".

, там всё равно все доступы к структуре будут обёрнуты в hton / ntoh.

C какого бодуна, если это зависит от протокола и контрорлера.

 

 

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


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

Городить какую-то функцию, которая будет разбитаться как именно невыровнен адрес а может и выровнен.... тода уж memcpy() - эта занимается тем-же самым, но понятно, что делает.

И все это ради того, что-бы отвергать великолепный механизм паковки и доступа к структурам. Дурдом.

Этот великолепный механизм - костыли которые в каждом компиляторе сделаны (и хорошо если в каждом) по своему.

Вон у TI, TCP стэк для msp430, как-то обошлись без великолепных механизмов.

И раз уж Вы так близки к задачам обмена данными, не приведёте код объявления упакованной структуры который любой С компилятор поймёт?

C какого бодуна, если это зависит от протокола и контрорлера.

endiannes у всех всех контроллеров вдруг стала одинаковая и так получиться так что она будет отличаться от заданной в протоколе никак не может?

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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