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

Здравствуйте. Я программирую на языке C для микроконтроллеров AVR при помощи компилятора gcc. Нашел такую интересную особенность. В приведенном ниже коде программа занимает место порядка 200 байт. Если раскомментировать закомментированную строку с объявлением функции delay_ms, программа резко полнеет до 350 байт. Никак не могу разобраться, почему. Не могли бы вы мне помочь. Упорное чтение Кернигана и Ричи не помогает. Куда гуглить просто не знаю. Заранее спасибо за ответ.

 

#define WDR        asm("wdr")
//void delay_ms(int time);

void main(void)
{
    delay_ms(1);
    delay_ms(1);
}


void delay_ms(int time)
{
    volatile int Timer, Timer1;

    for (Timer=0; Timer<time; Timer++)
        for (Timer1=0; Timer1<51; Timer1++)
            WDR;
}

 

 

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

 

-Wall
-gdwarf-2
-Os
-std=gnu99
-funsigned-char
-funsigned-bitfields
-fpack-struct
-fshort-enums

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


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

Здравствуйте. Я программирую на языке C для микроконтроллеров AVR при помощи компилятора gcc. Нашел такую интересную особенность. В приведенном ниже коде программа занимает место порядка 200 байт. Если раскомментировать закомментированную строку с объявлением функции delay_ms, программа резко полнеет до 350 байт. Никак не могу разобраться, почему. Не могли бы вы мне помочь. Упорное чтение Кернигана и Ричи не помогает. Куда гуглить просто не знаю.

А какой варнинг он выдает когда строка закомментирована?

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


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

Build succeeded with 0 Warnings...

Стало жутко интересно. Сделал проект и получил 230 байт в обоих случаях, только при закомментированном прототипе выдаются варнинги:

 

implicit declaration of function 'delay_ms'

conflicting types of function 'delay_ms'

 

С этим, надеюсь, понятно? При неявном использовании функции они считается возвращающей int, а когда компилятор дошел до ее определения, она оказалась void

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


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

Компилирую при помощи WinAVR-20081205, прикрученном к AVR Studio 4.16.

 

При неявном использовании функции они считается возвращающей int, а когда компилятор дошел до ее определения, она оказалась void

 

Про это я читал. Пробовал вместо void ставить int, но ситуация не меняется.

 

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

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


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

Компилирую при помощи WinAVR-20081205, прикрученном к AVR Studio 4.16.

 

Про это я читал. Пробовал вместо void ставить int, но ситуация не меняется.

 

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

 

4.18 b700 WinAVR 20100110

Еще имеет значение чип, я выбрал ATmega168

 

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


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

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

 

Вот еще один путь снижения объема кода

 

void delay_ms(int time)
{
    int Timer1 = 51;

    while(time--)
       while(Timer1--)
           WDR;
}

 

Здесь переменная Timer вообще не нужна.

Операция сравнения с нулем выполняется быстрее, чем с каким-либо другим числом.

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


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

void delay_ms(int time)
{
    int Timer1 = 51;

    while(time--)
       while(Timer1--)
           WDR;
}

Не знаю как себя поведёт avr-gcc, но в аннотации к mspgcc про такую конструкцию написано, что при удачном стечении обстоятельств ждать будем вечно...

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


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

4.18 b700 WinAVR 20100110

Еще имеет значение чип, я выбрал ATmega168

Спасибо! Завтра попробую скачать эту версию, посмотрю что получится.

 

 

 

 

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

 

Если не использовать volatile, то компилятор может оптимизировать задержку, т.е. просто выполнить конечный результат функции.

 

Вот еще один путь снижения объема кода

 

Вопрос не в том как сделать код задержки меньше, а почему при объявлении функции код увеличивается?

 

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


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

Вопрос не в том как сделать код задержки меньше, а почему при объявлении функции код увеличивается?

Посмотрите листинги для каждого случая, возможно, станет более понятно.

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


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

Если не использовать volatile, то компилятор может оптимизировать задержку, т.е. просто выполнить конечный результат функции.
А если напишете #define WDR asm volatile ("wdr"), то не сможет.

 

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


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

Не знаю как себя поведёт avr-gcc, но в аннотации к mspgcc про такую конструкцию написано, что при удачном стечении обстоятельств ждать будем вечно...

 

А там случайно эти обстоятельства не конкретизируются?

 

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


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

Вопрос не в том как сделать код задержки меньше, а почему при объявлении функции код увеличивается?

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

 

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


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

А там случайно эти обстоятельства не конкретизируются?

 

18. If you execute

while ((long) a & 0x80000l);

the program will hang, unless ’a’ is declared volatile. So, do it!

 

19. Delay loops are very sophisticated routines. Normally, users do something like:

int i = 1234;

while (i--);

or

int i;

for (i = 0; i < 1234; i++);

NEITHER WILL WORK AS YOU EXPECT when optimisation is switched on!!! The optimizer will detect

dead code in both examples and will eliminate it. It might even eliminate the loop completely. Adding the

volatile attribute to the definition of ’i’ might help, but don’t count on it if ’i’ is a local variable. The

compiler can still detect the calculations are wasteful, and eliminate them.

Regardless of these optimisation issues, this type of delay loop is poor programming style - you have no

idea how long or short a delay it might produce (although there is an obvious minimum bound!). It would be

better, and more reliable to define something like:

static void __inline__ brief_pause(register unsigned int n)

{

__asm__ __volatile__ (

"1: \n"

" dec %[n] \n"

" jne 1b \n"

: [n] "+r"(n));

}

and call this routine where needed. This is simple, compact, and predictable.

Хотя, я пробовал - иногда прокатывало...

Но тут уж как повезёт.

 

Основной смысл последней цитаты - задержку лучше определить самому (с точностью до такта), чем отдавать на откуп компилятору

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


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

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

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

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

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

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

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

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

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

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