Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Размер unsigned int или int Keil4.5
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > Keil
Страницы: 1, 2
TAutomatic
Добрый день, коллеги.
Месяц использую LPC1768 и только сейчас с "ужасом" заметил, что под переменные unsigned int и int компилятор отводит по 4 байта.
Использую среду Keil 4.5 и постоянно плююсь даже не по причине ее скудости, а по причине неудобности документации на нее и компилятор. Как установить "нормальный" размер этих типов данных размером в 2 байта?
И второй вопрос. Я был уверен, что в Cortex-M3 отсутствует необходимость выравнивания разноразмерных типов данных.
Об этом написано тут
Тем не менее, у себя в реале я этого не вижу. Если за однобайтовой переменной следует четырехбайтовая, то она все равно выравнивается по границе 32 разрядного слова, тоесть остается неиспользуемый промежуток в 3 байта. Что тут не так?
ohmjke
Размер int равен размеру машинного слова. В данном случае 32 бита.
Нужно 2 байта - используйте short int (ну или просто short), либо int16_t.
aaarrr
Цитата(TAutomatic @ Jun 2 2012, 15:17) *
Как установить "нормальный" размер этих типов данных размером в 2 байта?

Никак. 32-х битный int для 32-х битной архитектуры - это и есть норма. Используйте short или типы из <stdint.h>.

Цитата(TAutomatic @ Jun 2 2012, 15:17) *
И второй вопрос. Я был уверен, что в Cortex-M3 отсутствует необходимость выравнивания разноразмерных типов данных.
Об этом написано тут
Тем не менее, у себя в реале я этого не вижу. Если за однобайтовой переменной следует четырехбайтовая, то она все равно выравнивается по границе 32 разрядного слова, тоесть остается неиспользуемый промежуток в 3 байта. Что тут не так?

Необходимость необходимости рознь - эффективность работы с выровненными данными выше, поэтому без нужды паковать их не следует.
Используйте в случае нужды модификатор __packed.
TAutomatic
Цитата(ohmjke @ Jun 2 2012, 14:27) *
Размер int равен размеру машинного слова. В данном случае 32 бита.

Как бы такое утверждение было в основном принято к процессорам семейства х86. Для микроконтроллеров подразумевалось int - 2 байта. Но готов с Вами согласиться, поскольку в Keil нашел предопределенный макрос, который возвращает 4. Но тогда, по логике, long должен иметь удвоенный размер, только не машиннго слова, как Вы написали , поскольку это не команда, а размер шины данных, тоесть 64 бита. Разве не так?
ohmjke
Цитата
Машинное слово — машиннозависимая и платформозависимая величина, измеряемая в битах или байтах (тритах или трайтах), равная разрядности регистров процессора и/или разрядности шины данных.


И где это для МК подразумевалось 2 байта? У AVR?

Еще из википедии:
Цитата
Многие языки программирования предлагают выбор между короткими (англ. short), длинными (англ. long) и целыми стандартной длины. Длина стандартного целого типа, как правило, совпадает с размером машинного слова на целевой платформе. Для 16-разрядных операционных систем - этот тип (int) составляет 2 байта и совпадает с типом short int (можно использовать как short, опуская слово int), для 32-разрядных операционных систем он будет равен 4 байтам и совпадает с длинным целым long int (можно использовать как long, опуская слово int), и в этом случае будет составлять 4 байта. Короткое целое short int, для 16-разрядных операционных систем, 32-разрядных операционных систем, 64-разрядных операционных систем составляет — 2 байта. Также в некоторых языках может использоваться тип данных двойное длинное long long, который составляет 8 байт.
TAutomatic
Цитата(aaarrr @ Jun 2 2012, 14:30) *
Используйте в случае нужды модификатор __packed.

Так можно упаковать только структуры и битовые поля, не так ли?
Переменные базовых типов так не упакуешь.

Цитата(ohmjke @ Jun 2 2012, 14:37) *
И где это для МК подразумевалось 2 байта?

Еще из википедии:

Я согласен с Вами, офицального признания, что int- это 2 байта, нет. Это есть определенное неофицальное соглашение. Впрочем, нет смысла спорить, да я и не за тем спрашиваю. В большенстве систем, даже 32х или даже 64х разрядных есть двухбайтовые типы данных.
Получается, в ARM нет двухбайтового типа данных?
ohmjke
Написали же, 2 байтовый это short.
TAutomatic
Получается, все же есть в <stdint.h> - short


Цитата(TAutomatic @ Jun 2 2012, 14:46) *
Получается, все же есть в <stdint.h> - short

Я увидел, благодарствую.
aaarrr
Цитата(TAutomatic @ Jun 2 2012, 15:43) *
Переменные базовых типов так не упакуешь.

А вы попробуйте wink.gif
ohmjke
short он не из stdint.h, а просто является частью языка.
а в stdint.h вот что - http://ru.wikipedia.org/wiki/Stdint.h
TAutomatic
Цитата(aaarrr @ Jun 2 2012, 14:49) *
А вы попробуйте wink.gif

Подскажите метод, как упаковать?
Код
unsigned char A;
unsigned long B;
unsigned char C;

что бы получилось занятыми в памяти не 12 байт, а 6 байт?
Буду весьма благодарен.
prottoss
Цитата(TAutomatic @ Jun 2 2012, 17:53) *
Подскажите метод, как упаковать? ...что бы получилось занятыми в памяти не 12 байт, а 6 байт?

Вам же выше уже говорили про __packed. Создаете структуру с требуемым набором данных. Сообщаете компилятору, что нужно ее упаковать и готово.

Кстати, для определения типов пользуюсь давным-давно уже своим хедером:
Код
/*******************************************************************************
Declared types
*******************************************************************************/

/* Integer */
typedef signed int            INT, *P_INT;
typedef unsigned int        UINT, *P_UINT;
#define MAXUINT                ((UINT)(-1))
#define INTLEN                (sizeof(INT))

/* byte */
typedef signed char            CHAR, *P_CHAR;
typedef unsigned char        UCHAR, *P_UCHAR;

typedef CHAR                INT8, *P_INT8;
typedef UCHAR                UINT8, *P_UINT8;
#define MAXUINT8            ((UINT8)(-1))
#define INT8LEN                (sizeof(INT8))

/* word */
typedef signed short        INT16, *P_INT16;
typedef unsigned short        UINT16, *P_UINT16;
#define MAXUINT16            ((UINT16)(-1))
#define INT16LEN            (sizeof(INT16))

/* double word */
typedef signed long            INT32, *P_INT32;
typedef unsigned long        UINT32, *P_UINT32;
#define MAXUINT32            ((UINT32)(-1))
#define INT32LEN            (sizeof(INT32))

/* quad word */
typedef signed long long    INT64, *P_INT64;
typedef unsigned long long    UINT64, *P_UINT64;
#define MAXUINT64            ((UINT64)(-1))
#define INT64LEN            (sizeof(INT64))

Один файл для всех типов МК, в том числе AVR и ARM
ivainc1789
Не хотел создавать новую тему... Можно ли спросить здесь:
1. В связи с чем в IAR определены типы uint16_t и подобные, оканчивающиеся на "_t". Всю жись писал полностью "unsigned int" и так далее... Так конечно длиннее и дольше, больше тонера при распечатках, но уже привычно... Зачем эти "_t" определили?
2. Есть ли в IAR возможность подсветить эти типы жирным шрифтом, как стандартные?
ohmjke
Цитата(ivainc1789 @ Jun 2 2012, 16:21) *
Не хотел создавать новую тему... Можно ли спросить здесь:
1. В связи с чем в IAR определены типы uint16_t и подобные, оканчивающиеся на "_t". Всю жись писал полностью "unsigned int" и так далее... Так конечно длиннее и дольше, больше тонера при распечатках, но уже привычно... Зачем эти "_t" определили?
2. Есть ли в IAR возможность подсветить эти типы жирным шрифтом, как стандартные?

Это не только в IAR.
Думаю, просто для удобства - короче и сразу видно размер.
И лично для меня так действительно удобнее.
prottoss
Цитата(ivainc1789 @ Jun 2 2012, 18:21) *
Зачем эти "_t" определили?
Это типа сообщение человечеству, что это "тип данных". Я например (по рекомендации мелкософтаwink.gif) Глобальные переменные называю с первыми символами "g_" (global). Например "g_SysTime". Так же и здесь - uint16_t (uint16 type)
TAutomatic
Цитата(prottoss @ Jun 2 2012, 15:20) *
Вам же выше уже говорили про __packed. Создаете структуру с требуемым набором данных. Сообщаете компилятору, что нужно ее упаковать и готово.

Подождите, я Вам также и возразил. Пакед относится к структурам, а не к базовым типам данных. А Вы утверждаете ниже, что и к базовым типам тоже применимо. А приводите в пример все же структуры. Давайте отделим мух от котлет. Со структурами все понятно.
Базовые типы упаковать как можно? есть у вас ответ? Если у меня есть в разных программных модулях глобальные переменные, но в пределах видимости определенных модулей, на кой их мне сносить в одну гигантскую структуру? Это что- удобно? А вот что бы переменные были упакованы - тоже необходимо. Эффективность работы с такими переменными-второй вопрос. Первый - размер в ОЗУ.
aaarrr
Цитата(TAutomatic @ Jun 2 2012, 15:53) *
Подскажите метод, как упаковать?
Код
unsigned char A;
unsigned long B;
unsigned char C;

что бы получилось занятыми в памяти не 12 байт, а 6 байт?
Буду весьма благодарен.

Сами решили не пробовать даже?
Код
unsigned char a;
__packed unsigned long b;
unsigned char c;
TAutomatic
Цитата(aaarrr @ Jun 2 2012, 15:43) *
Сами решили не пробовать даже?
Код
unsigned char a;
__packed unsigned long b;
unsigned char c;

Дело не в том, что решил или нет. Дело в том, что я не на работе. А на домашнем компе рабочих программ принципиально не имею. Но в первый рабочий день обязательно испробую. Но меня чисто теоретически гложат смутные сомнения, что дает этот квалификатор применимо к одной строчке? В моем представлении, это должна быть какая-то либо глобальная директива на всю программу, либо на программный модуль, либо на некую секцию данных. Только тогда он будет работать. Но если вы утверждаете, остается попробовать и убедиться....
prottoss
Цитата(aaarrr @ Jun 2 2012, 18:43) *
Код
unsigned char a;
__packed unsigned long b;
unsigned char c;
Наверное все же
Код
__packed unsigned char a;
unsigned long b;
__packed  unsigned char c;
?
Хотя я сам такой ерундой не баловался sm.gif
aaarrr
Цитата(prottoss @ Jun 2 2012, 16:56) *
Наверное все же

Нет. Какой смысл паковать char, если он и так упакован по определению?

Цитата(TAutomatic @ Jun 2 2012, 16:54) *
Но меня чисто теоретически гложат смутные сомнения, что дает этот квалификатор применимо к одной строчке?

Позволит разместить переменную без выравнивания. Глобально подобные вещи не практикуются, т.к. такой подход просто убьет производительность.
Аккуратно размещать данные, чтобы не было перерасхода на padding'и, программист должен самостоятельно.
prottoss
Цитата(aaarrr @ Jun 2 2012, 19:05) *
Нет. Какой смысл паковать char, если он и так упакован по определению?
Я почему то думал, что компилятор два "char" ('a' и 'c') упакует в одно 32-бит слово, а 'b' поместит в другое.

Но вот работа с этими самыми 'a' и 'c' - это очевидно - будет достаточно медленна.
aaarrr
Char может быть расположен как угодно - на скорости это не скажется. А вот short, int и т.п. лучше выравнивать, что компилятор и делает по умолчанию.
prottoss
Цитата(aaarrr @ Jun 2 2012, 19:28) *
Char может быть расположен как угодно - на скорости это не скажется. А вот short, int и т.п. лучше выравнивать, что компилятор и делает по умолчанию.
Стоп-стоп. Что то я Вас не понимаю... Зачем выравнить 'int' если он по умолчанию и так ляжет в 32-бит слово??? То же самое относится к типу 'long'. Для 32-бит систем эти типы одинаковы по размерности.
А вот как раз с 8/16-бит переменными ('char' и 'short') сложности по производительности.
Допустим, вы объявили три переменные трех разных типов:
Код
__packed char a;
__packed short b;
__packed long c;

С переменной 'c' и так все ясно, она 32-бит и компилятор положит ее в память по выровненному 32-бит адресу.
С переменными 'а' и 'c' начинаются сложности. Компилятор положит их в 32-бит ячейку вместе. Т.е. у одной из переменных, в зависимости от решения компилятора будет не выровненный адрес. У какой - не известно sm.gif Все зависит от интеллекта компилятора... Возможно, я заблуждаюсь?

Цитата(aaarrr @ Jun 2 2012, 19:28) *
Char может быть расположен как угодно - на скорости это не скажется.

Код
__paced short a;
__packed char i;

for(i = 0; i++; i < MAXCYCLE)
{  
   ....
}

Интересно, скажется ли на производительности цикла то, в каком байте 32-бит слова будет расположена переменная 'i'? В младшем из 4-х байтов или в 3-ем?
aaarrr
Цитата(prottoss @ Jun 2 2012, 17:50) *
С переменной 'c' и так все ясно, она 32-бит и компилятор положит ее в память по выровненному 32-бит адресу.

Нет, ведь мы позволили разместить ее как угодно (__packed).

Цитата(prottoss @ Jun 2 2012, 17:50) *
С переменными 'а' и 'c' начинаются сложности. Компилятор положит их в 32-бит ячейку вместе. Т.е. у одной из переменных, в зависимости от решения компилятора будет не выровненный адрес. У какой - не известно sm.gif Все зависит от интеллекта компилятора... Возможно, я заблуждаюсь?

Объясните мне, как у char'а размерностью один байт может быть не выравнен адрес?
Если вы объявили переменную как __packed, компилятор по определению работает с ней как с не выравненной, несмотря на реальный адрес.

Цитата(prottoss @ Jun 2 2012, 17:50) *
Интересно, скажется ли на производительности цикла то, в каком байте 32-бит слова будет расположена переменная 'i'? В младшем из 4-х байтов или в 3-ем?

Разумеется, нет.
prottoss
Цитата(aaarrr @ Jun 2 2012, 20:02) *
Объясните мне, как у char'а размерностью один байт может быть не выравнен адрес?
Все, от перегрева на солнце, я погнал. sm.gif Извините. Вы, безусловно, были правы.
scifi
Цитата(TAutomatic @ Jun 2 2012, 16:54) *
Но меня чисто теоретически гложат смутные сомнения, что дает этот квалификатор применимо к одной строчке?

Чтобы сомнения не терзали, предлагаю обращаться к первоисточнику. Понятно, что это скучно и не позволяет поговорить "за жизнь", но информацию даёт на ура.
TAutomatic
Цитата(aaarrr @ Jun 2 2012, 16:05) *
Нет. Какой смысл паковать char, если он и так упакован по определению?


Позволит разместить переменную без выравнивания. Глобально подобные вещи не практикуются, т.к. такой подход просто убьет производительность.
Аккуратно размещать данные, чтобы не было перерасхода на padding'и, программист должен самостоятельно.

Первый мой рабочий день новой недели позволяет мне Вам сказать спасибо. Действительно, квалификатор пакует, убедился своими глазами. Честно говоря, как для меня, документация KEIL на свою среду не очень удобна. Наверно, дело привычки. Сразу в хелпе, что идет со средой не разобраться. На сайте кажется даже более удобно. Но это лично мое мнение, нет повода для споров. А вам, aaarrr еще раз спасибо.
esaulenka
Я бы предложил не заниматься всякой фигнёй. Особенно если нет твёрдого понимания, что вообще происходит.
__packed, конечно, экономит память, но заметно сказывается на объеме программы (на не-кортексах) и на производительности (на любых армах).

Кейл (в частности, 4.14 с включенным оптимизатором) достаточно догадлив, чтобы собрать данные в одну кучу.

Код
volatile char var_a;
volatile int var_b;
volatile char var_c;
int main(void)
{
    var_a = IOPIN0;
    var_b = IOPIN1;
    var_c = var_a + var_b;
    IOPIN0 = var_c;
    while (1);
}


Код
    var_a                                    0x40000000   Data           1  main.o(.data)
    var_c                                    0x40000001   Data           1  main.o(.data)
    var_b                                    0x40000004   Data           4  main.o(.data)
TAutomatic
Цитата(esaulenka @ Jun 5 2012, 14:40) *
Я бы предложил не заниматься всякой фигнёй. Особенно если нет твёрдого понимания, что вообще происходит.
__packed, конечно, экономит память, но заметно сказывается на объеме программы (на не-кортексах) и на производительности (на любых армах).

Кейл (в частности, 4.14 с включенным оптимизатором) достаточно догадлив, чтобы собрать данные в одну кучу.


А я бы постеснялся давать такие советы. Я думаю, на "месте" виднее, "фигня или не фигня". Для кого-то аккуратность распределения памяти, а для кого-то фигня. Но давать такого рода советы вместо технических - отсутствие воспитания. А насчет твердого понимания - это наверно из соседней темы? :-)
IgorKossak
Цитата(esaulenka @ Jun 5 2012, 14:40) *
Кейл (в частности, 4.14 с включенным оптимизатором) достаточно догадлив, чтобы собрать данные в одну кучу.
Код
    var_a                                    0x40000000   Data           1  main.o(.data)
    var_c                                    0x40000001   Data           1  main.o(.data)
    var_b                                    0x40000004   Data           4  main.o(.data)

Кейлу следовало бы быть более тщательным в своей "догадливости" и разместить данные в порядке: var_b, var_a, var_c. Т. е. без разрыва, который в Вашем примере имеет место быть.
Dron_Gus
Цитата(IgorKossak @ Jun 6 2012, 00:08) *
Кейлу следовало бы быть более тщательным в своей "догадливости" и разместить данные в порядке: var_b, var_a, var_c. Т. е. без разрыва, который в Вашем примере имеет место быть.

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

Кстати, __packed char на производительность не влияет. А вот __packed short уже влияет. Даже на архитектурах, позволяющих невыравненное обращение.
TAutomatic
Цитата(esaulenka @ Jun 5 2012, 14:40) *
Я бы предложил не заниматься всякой фигнёй. Особенно если нет твёрдого понимания, что вообще происходит.
__packed, конечно, экономит память, но заметно сказывается на объеме программы (на не-кортексах) и на производительности (на любых армах).

Кейл (в частности, 4.14 с включенным оптимизатором) достаточно догадлив, чтобы собрать данные в одну кучу.

Код
volatile char var_a;
volatile int var_b;
volatile char var_c;
int main(void)
{
    var_a = IOPIN0;
    var_b = IOPIN1;
    var_c = var_a + var_b;
    IOPIN0 = var_c;
    while (1);
}


Код
    var_a                                    0x40000000   Data           1  main.o(.data)
    var_c                                    0x40000001   Data           1  main.o(.data)
    var_b                                    0x40000004   Data           4  main.o(.data)


Этот автор либо вообще решил подыграть Кейлу, написав пример "от руки", либо не понятно, кто страдает "фигней". Если автор от руки написал пример, чувствуется твердое понимание происходящего, а именно процедура упаковки. Между переменными var_c и var_b оставлена "дырка" в 2 байта, это называется "достаточной догадливостью"? А если это результат реальной работы компилятора, у меня возникает вопрос: компилятор вправе даже при использовании оптимизатора так вольно тусовать переменные? На каком основании он поменял местами переменные относительно их объявления? Да, они не привязаны к адресам, компилятор волен их свободно размещать во всем адресном пространстве. Но порядок их должен быть таким, как при объявлении. Во всяком случае, так было во всех компиляторах, которые я пользовал до Кейла.
ViKo
Цитата(TAutomatic @ Jun 6 2012, 07:53) *
На каком основании он поменял местами переменные относительно их объявления?

Вставил a в первое же подходящее место. Вставил b в первое же подходящее место, по выровненному адресу. Вставил c, аналогично. Первое же подходящее место для с где? Правильно!
TAutomatic
Цитата(ViKo @ Jun 6 2012, 08:33) *
Вставил a в первое же подходящее место. Вставил b в первое же подходящее место, по выровненному адресу. Вставил c, аналогично. Первое же подходящее место для с где? Правильно!

rolleyes.gif Компилятор - не человек. Он не может, да не имеет права так вольно перемещать, менять местами порядок переменных. Упаковать-это одно, порядок не нарушается, а поменять местами-это другое. А вдруг такой порядок - задумка программиста? А компилятор все нарушил. Разницу в упаковке что есть и перемещении с целью "оптимизации" чувствуете? rolleyes.gif
demiurg_spb
Цитата(TAutomatic @ Jun 6 2012, 09:22) *
вдруг такой порядок - задумка программиста?
тогда в структуре и объявляете поля с определённым порядком, который никто не нарушит. А так компилятор волен делать что угодно в пределах стандарта.
IgorKossak
Цитата(TAutomatic @ Jun 6 2012, 09:22) *
А вдруг такой порядок - задумка программиста?

Упование на порядок переменных - моветон, причина необъяснимых глюков и бесконечные наезды на компилятор.
ViKo
Цитата(TAutomatic @ Jun 6 2012, 09:22) *
А вдруг такой порядок - задумка программиста? А компилятор все нарушил.

У переменных, независимых друг от друга, нет и не может быть никакого "порядка". Об этом и в книжках пишут, и самому можно догадаться.
У компилятора (или линкера) одна цель - впихнуть впихуемое. Берет переменные попорядку, и пихает их, куда можно. Никакой фантазии, дубовая логика.

__packed, кстати, относится только к структурам и объединениям, целиком, или к отдельным их составляющим. Для обычных переменных этот атрибут ничего не дает. Я так думаю. sm.gif
И, получается, aaarrr не прав.
TAutomatic
Цитата(ViKo @ Jun 6 2012, 11:43) *
У переменных, независимых друг от друга, нет и не может быть никакого "порядка". Об этом и в книжках пишут, и самому можно догадаться.
У компилятора (или линкера) одна цель - впихнуть впихуемое. Берет переменные попорядку, и пихает их, куда можно. Никакой фантазии, дубовая логика.

Вы глубоко ошибаетесь, так утверждая. Такого уж точно "в книжках не пишут". Есть такое понятие - секции. В том числе данных. Это не структурированные типы данных. Это переменные в том числе и базовых типов? Задумайтес, для чего придумали секции? Вы секциями пользуетесь?
У компилятора другая цель - транслировать конструкции языков верхнего уровня в ассемблерные инструкции. Линкер предназначен для объединения объектного кода в общее целое с расстановкой физических адресов. Они оба ничего никуда не впихивают. Об этом нужно четко знать, если вы читаете книжки, в которых что-то пишут. А вот "впихивать" - это задача оптимизатора. И эта задача распространяется на код, а не на данные. Тоже в книжках написано, которые стоит читать.
Цитата(ViKo @ Jun 6 2012, 11:43) *
__packed, кстати, относится только к структурам и объединениям, целиком, или к отдельным их составляющим. Для обычных переменных этот атрибут ничего не дает. Я так думаю. sm.gif
И, получается, aaarrr не прав.

Думать Вам, естественно, никто не запрещает. Но вот, прежде чем писать, что кто-то не прав-желательно самому убедиться в этом. Одну страницу назад я спрашивал об упаковке данных, и когда aaarrr ответил, я не стал утверждать ничего. Пока не смогу сам лично убедиться, что бы не "сесть в лужу". Я убедился сам реально, что __packed применим и к базовым типам данным и действительно упаковывает переменные базовых типов до минимальных размеров, тоесть до логических размеров в байтах. И aaarrr прав, а Вы вот сейчас "сели в лужу", основываясь только на думании, а не на практике.
ViKo
Цитата(TAutomatic @ Jun 6 2012, 15:31) *
Я убедился сам реально, что __packed применим и к базовым типам данным и действительно упаковывает переменные базовых типов до минимальных размеров...

Я проверил пример из сообщения №28 еще утром. Прежде, чем писать. Сейчас проверил еще раз. Добавьте к переменной var_b атрибут __packed, скомпилируйте, и удивите меня фрагментом из map файла, если переменная var_b окажется расположенной по невыровненному адресу.
А потом поговорим о том, кто "убедился сам реально", а кто "сел в лужу". После, чем писать sm.gif

Кроме того, почитайте, что написано про __packed в первоисточнике - помощи по Keil.
P.S. Цитату из книжки позже приведу.
TAutomatic
Цитата(ViKo @ Jun 6 2012, 16:05) *
Я проверил пример из сообщения №28 еще утром. Прежде, чем писать. Сейчас проверил еще раз. Добавьте к переменной var_b атрибут __packed, скомпилируйте, и удивите меня фрагментом из map файла, если переменная var_b окажется расположенной по невыровненному адресу.
А потом поговорим о том, кто "убедился сам реально", а кто "сел в лужу". После, чем писать sm.gif

Кроме того, почитайте, что написано про __packed в первоисточнике - помощи по Keil.
P.S. Цитату из книжки позже приведу.

Не обижайтесь, хорошо? rolleyes.gif Бывает, даже самые знатоки иногда банальных вещей не знают. А по теме вот что:
Код:
Код
unsigned char a;
unsigned int    b;
unsigned char c;

у меня в мап-файле дает вот что:
Код
    a                                        0x100000fc   Data           1  tx11main.o(.data)
    b                                        0x10000100   Data           4  tx11main.o(.data)
    c                                        0x10000104   Data           1  tx11main.o(.data)

а вот такой код
Код
__packed unsigned char a;
__packed unsigned int    b;
__packed unsigned char c;

имеет результатом вот что:
Код
    a                                        0x100000fc   Data           1  tx11main.o(.data)
    b                                        0x100000fd   Data           4  tx11main.o(.data)
    c                                        0x10000101   Data           1  tx11main.o(.data)

Мне кажется тут и комментировать нечего. Кеил 4.5 Я не знаю почему и для чего оптимизатор у Вас или у кого-то еще что-то переставляет. При чем тут вообще оптимизатор. Вот, простой пример упаковки. Логических 6 байт упакованы в 6 адресов, лучше не придумаешь. Что еще тут можно спорить. Если у кого-то не так-посмотрите, все ли вы правильно пишите. И почитайте книжки. Так что aaarrr прав, и я ему свое спасибо уже сказал.
ViKo
Проверил с тремя __packed. Так я не пробовал.
var_a 0x20000000 Data 1
var_c 0x20000001 Data 1
var_b 0x20000002 Data 4
Да, упаковалось. Вы правы.

Проверил и с двумя, одним. Тоже укладывается. Оказывается, я не обновлял map файл при просмотре, а Total Commander показывал мне старый.
aaarrr прав! Я - посрамлен! crying.gif Keil - обманщик.
TAutomatic
Цитата(ViKo @ Jun 6 2012, 17:01) *
Проверил с тремя __packed. Так я не пробовал.
var_a 0x20000000 Data 1
var_c 0x20000001 Data 1
var_b 0x20000002 Data 4
Да, упаковалось. Вы правы.

Ну и слава Богу, разобрались. rolleyes.gif Если кому поможет тоже эта информация - это чудненько, больше будет знатоков. Думаю, топик можно закрыть.
andrewlekar
Ребята, я вас умоляю, не делайте так в рабочем коде. Придёт после вас человек и не поймёт нифига, что вы там наоптимизировали.
ViKo
Герберд Шилдт. Полный справочник по C. (в электронном виде не имею на русском языке, в книжке на русском еще понятнее).
Page 144 - 145
Цитата
Another error that sometimes occurs is caused by incorrect assumptions about the placement of
variables in memory. In general, you cannot know where your data will be placed in memory, or
whether it will be placed there the same way again, or whether different compilers will treat it in the
same way. For these reasons, making any comparisons between pointers that do not point to a
common object may yield unexpected results. For example,

char s[80], y[80];
char *p1, *p2;
p1 = s;
p2 = y;
if(p1 < p2) . . .

is generally an invalid concept. (In very unusual situations, you might use something like this to
determine the relative position of the variables. But this would be rare.)

A related error results when you assume that two adjacent arrays may be indexed as one by simply
incrementing a pointer across the array boundaries. For example:

int first[10], second[10];
int *p, t;
p = first;
for(t=0; t<20; ++t) *p++ = t;

This is not a good way to initialize the arrays first and second with the numbers 0 through 19. Even
though it may work on some compilers under certain circumstances, it assumes that both arrays will
be placed back to back in memory with first first. This may not always be the case.
TAutomatic
Цитата(andrewlekar @ Jun 7 2012, 07:45) *
Ребята, я вас умоляю, не делайте так в рабочем коде. Придёт после вас человек и не поймёт нифига, что вы там наоптимизировали.

А при чем тут придет и не поймет rolleyes.gif Я беру к себе на работу только тех, кто способен понимать и разобраться. Тогда и Вы ответьте на вопрос: зачем тогда столько "фишек" и примочек в компиляторе? Вы этим не пользуетесь? Я пользуюсь. И максимально, что бы был максимально эффективный код, или максимально эффективное решение задачи или еще что-то в этом роде, но максимально эффективное. Почему публика привратно в основном понимает эту суть. если я спросил насчет упаковки переменных, почему -т о в основном у публики сложилось сразу впечатление, что я возьму тупо все данные упакую в кирпич. И начались советы по поводу эффективности такого использования и т.д. и т.п. Ребята, я не собираюсь так делать rolleyes.gif Во всяком случае ко всему подряд и без разбора "на всякий случай". Просто иногда гдето-то в определенном месте в связи с определенными условиями нужно применить такой метод. И не более. Речь не идет о како-то глобальности. Если Вы не пользуетесь всеми инструментами, которые вам дает средство разработки, Вы либо невысокой квалификации специалист, либо не можете предложить самое эффективное решение задачи, что собственно тоже говорит о квалификации. Все, что правильно понимается и правильно применяется- никак не отражается на рабочем коде в подавляющем большенстве случаев. И почти все так называемые "глюки" контроллеров или среды - это глюки того, кто не в полной мере этим владеет. Низкая квалификация.

Цитата(ViKo @ Jun 7 2012, 08:53) *
Герберд Шилдт. Полный справочник по C. (в электронном виде не имею на русском языке, в книжке на русском еще понятнее).
Page 144 - 145

Все правильно, спасибо за цитату rolleyes.gif Теперь попытаюсь Вам концептуально разъяснить в чем дело. Язык С был создан в эпоху микропроцессоров, у которых память была сегментирована. Это процессоры чуть до Intel286 и 386 и в том числе эти процессоры. Так вот, что бы получить доступ к исполнительному адресу, нужно было еще опереровать с сегментным регистром. Вполне вероятно, что два массива по 10 байт оказались бы на границе сегмента. Физически это последовательные адреса, но вот логические уже нет. И тогда последовательное обращение к 20 байтам на самом деле бы привело не к обращению к двум последовательным массивам, а в пределах одного секмента 64кБ. Давайте жить реалиями сегняшнего дня. В основном все уже имеют дело с микроконтроллерами с линейным адресным пространством. В пределах этого пространства компилятор не занимается перестановкой переменных и оптимизацией их размещения, если на то нет особых инструкций, указаний и т. д. Тоесть, компилятор оптимизирует код с обязательным требованием сохранения его идентичности по функционалу исходному коду и не занимается оптимизацией памяти данных
andrewlekar
Цитата
А при чем тут придет и не поймет rolleyes.gif Я беру к себе на работу только тех, кто способен понимать и разобраться. Тогда и Вы ответьте на вопрос: зачем тогда столько "фишек" и примочек в компиляторе? Вы этим не пользуетесь?

Вы же сами наблюдали, как несколько человек с первого взгляда не поверили, что компилятор умеет паковать отдельные переменные. Придёт новый человек и тоже потратит время и нервы на то, чтобы снова выяснить то же самое. Нормальные люди, если требуется, пакуют структуры и пишут комментарии, для чего это делается. Фишки и примочки компилятора реализованы для того, чтобы:
1. Соответствовать стандарту языка. Стандарт языка может при этом содержать совершенно неадекватные конструкции и предположения. Но это стандарт и нужно соответствовать.
2. Для обхода узких мест.
3. Организация данных для соответствия неким стандартам. Например, упаковка данных для DMA или передачи по TCP.

Так что да, я фишками и примочками компилятора не пользуюсь без необходимости. А такой необходимости практически никогда не появляется, так как я закладываю заведомо способный реализовать задачу процессов, заведомо достаточное количество памяти, стандартные среды передачи и стандартные библиотеки для работы со всем этим добром.
В наше время, эффективный инженер - это не Левша и не Кулибин, а человек, способный качественно и в срок решить поставленную задачу, способный организовать поддержку своего решения и расширения функционала.
TAutomatic
Цитата(andrewlekar @ Jun 7 2012, 09:40) *
Вы же сами наблюдали, как несколько человек с первого взгляда не поверили, что компилятор умеет паковать отдельные переменные. Придёт новый человек и тоже потратит время и нервы на то, чтобы снова выяснить то же самое. Нормальные люди, если требуется, пакуют структуры и пишут комментарии, для чего это делается. Фишки и примочки компилятора реализованы для того, чтобы:
1. Соответствовать стандарту языка. Стандарт языка может при этом содержать совершенно неадекватные конструкции и предположения. Но это стандарт и нужно соответствовать.
2. Для обхода узких мест.
3. Организация данных для соответствия неким стандартам. Например, упаковка данных для DMA или передачи по TCP.

Так что да, я фишками и примочками компилятора не пользуюсь без необходимости. А такой необходимости практически никогда не появляется, так как я закладываю заведомо способный реализовать задачу процессов, заведомо достаточное количество памяти, стандартные среды передачи и стандартные библиотеки для работы со всем этим добром.
В наше время, эффективный инженер - это не Левша и не Кулибин, а человек, способный качественно и в срок решить поставленную задачу, способный организовать поддержку своего решения и расширения функционала.

Вы все правильно говорите и занимаете твердую позицию. Ладно. Но мне такая позиция не подходит. Знаете почему? Вокруг меня, кого я знаю, кроме моих сотрудников, никто не пользуется например DMA. А зачем? Вот аргументы, похожие на Ваши. Таких задач не появляется, все и так работает, памяти хватает, скорости тоже и т.д и т. п. Это позиция не для меня. Если такая возможность есть - нужно ее использовать. И знать где, как и правильно. И это - максимальная эффективность. А пытаться обходить... Ну знаете, обойти то все можно. Как раз вот это - кулибин. Не знает языка, не знает компилятора, всех его расширений -но выкрутился, решил задачу. Да еще так, что в ней может разобраться такой же кулибин без глубоких знаний. Я не в Вашу сторону и никого не хочу из публики обидеть, никаких личностей. Мой стиль им оих сотрудников - решать задачу используя все возможности в нужном месте естественно вплоть до недокументированных функций, если это работает корректно.
Dron_Gus
Цитата(TAutomatic @ Jun 7 2012, 10:18) *
Давайте жить реалиями сегняшнего дня. В основном все уже имеют дело с микроконтроллерами с линейным адресным пространством. В пределах этого пространства компилятор не занимается перестановкой переменных и оптимизацией их размещения, если на то нет особых инструкций, указаний и т. д. Тоесть, компилятор оптимизирует код с обязательным требованием сохранения его идентичности по функционалу исходному коду и не занимается оптимизацией памяти данных

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

Более того, при определенных настройках тот же GCC может перекладывать данные из секции .data в .bss
TAutomatic
Цитата(Dron_Gus @ Jun 7 2012, 10:22) *
С первой частью заявления не соглашусь. Пространство хоть и линейно, но это не гарантирует одинаковое время доступа и одинаковое количество инструкций для доступа в ряде случаев.
Соответственно оптимизатор вполне может перетасовать данные, если это обоснованно и даст какой-то профит.

Более того, при определенных настройках тот же GCC может перекладывать данные из секции .data в .bss

Послушайте, чесговоря нет времени на такого рода диспут, но когда пишут совершенно непонятные для меня вещи, хочется всегда спросить: откуда вы это взяли?!!! Ну откуда вы взяли что время доступа может быть разны, если переменные размещаются в ОЗУ? Мы же не ведем речь о переменных и сразу о константах, которые размещаются в адресном пространстве кода? Ну я вот хочу знать того, чего не знаю. Покажите мне не на пальцах, а на конкретном примере. И еще, какие такие настройки компилера позволят две однородные переменные без инициализации на стадии линковки или обе с инициализацией, расположенные в одном программном модуле последовательно друг за другом разнести по разным секциям? Пожете показать, как Вы это делаете? rolleyes.gif
jcxz
Цитата(TAutomatic @ Jun 7 2012, 14:16) *
Ну откуда вы взяли что время доступа может быть разны, если переменные размещаются в ОЗУ? Мы же не ведем речь о переменных и сразу о константах, которые размещаются в адресном пространстве кода? Ну я вот хочу знать того, чего не знаю. Покажите мне не на пальцах, а на конкретном примере.

Позвольте встрять? wink.gif

Кроме внутреннего ОЗУ, к контроллеру может быть подцеплено внешнее, с другим временем доступа.
Даже если есть только внутреннее, то в некоторых процессорах есть разные RAM с разным быстродействием, расположенные на разных шинах.
Или, к примеру: внутреннее ОЗУ разбито на банки (непрерывно расположенные в адресном пространстве), и одна из переменных - в одном банке, другая - в другом, а во второй банк как раз идёт интенсивное DMA (с приоритетом контроллера DMA) - здесь разница во времени доступа может быть ОЧЕНЬ большой.
Даже если банки ОЗУ в несмежных областях - линкер (при соотв. опциях) может разбить выходные секции на неск. несмежных областей.
Для каких-то областей может быть включено/выключено кеширование.
Или (типичная оптимизация IAR for ARM): функция работает с неск. статическими переменными - IAR заносит в некий базовый регистр указатель на область памяти, которая включает большую часть этих переменных и адресует их через этот базовый + смещение, а одна переменная - далеко от остальных, разрядности смещения не хватает и для обращения к ней компилятору приходится вставлять доп. инструкции загрузки адреса этой переменной в регистр - соответственно доступ к этой переменной будет дольше.

Перетасовка переменных оптимизатором - это большой гуд. ПО не должно привязываться к взаимному расположению переменных (конечно это не касается внутри структур).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.