реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Использование static переменных
777777
сообщение Oct 7 2010, 15:41
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Сергей Борщ @ Oct 7 2010, 00:09)
Оптимизатор вполне может выкинуть запись в любую переменную, будь то обычный int или массив, если он видит, что результат такой записи не используется (а с его точки зрения он не используется).


Насчет любой переменной вы погорячились - значения static переменных сохраняются даже после выхода из функции и будут иметь его при повторном входе в эту функцию.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 7 2010, 16:14
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Не совсем понятно из какого топика вырвана эта цитата, но вы исказили ее смысл, попустив слово "запись". По смыслу у Сергея Борща "выкинуть" не саму переменную, а выкинуть обращение к ней.
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 7 2010, 16:32
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(rezident @ Oct 7 2010, 20:14) *
Не совсем понятно из какого топика вырвана эта цитата,

Отсюда. Модераторы мудро решили ее закрыть.
Цитата(rezident @ Oct 7 2010, 20:14) *
но вы исказили ее смысл, попустив слово "запись".

Я не пропустил слово "запись"
Цитата(rezident @ Oct 7 2010, 20:14) *
По смыслу у Сергея Борща "выкинуть" не саму переменную, а выкинуть обращение к ней.

И обращение к ней (запись в нее) он не может выкинуть, так как должен знать, что результат может понадобиться при следующем обращении к ней. Если она static.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 7 2010, 16:43
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(777777 @ Oct 7 2010, 22:32) *
И обращение к ней (запись в нее) он не может выкинуть, так как должен знать, что результат может понадобиться при следующем обращении к ней. Если она static.
static относится к storage-class specifier, т.е. влияет лишь на размещение и область видимости объекта, но не влияет на оптимизацию обращения к данному объекту. Для предотвращения оптимизации обращения к объекту применяется квалификатор volatile, который наряду с const и restrict относится к квалификаторам типа (type qualifiers). См. стандарт C99 (ISO/IEC 9899:1999).
Прикрепленные файлы
Прикрепленный файл  C99_iso_iec_9899_1999.pdf ( 1.26 мегабайт ) Кол-во скачиваний: 70
 
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 7 2010, 17:11
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(777777 @ Oct 7 2010, 18:41) *
Насчет любой переменной вы погорячились - значения static переменных сохраняются даже после выхода из функции и будут иметь его при повторном входе в эту функцию.
Ключевой момент - "Если результат такой записи не используется". Т.е. если вы не читате из такой переменной, а только пишете, то такая запись - бесполезная трата тактов процессора. Я не уверен, является ли присвоение адреса переменной указателю сигналом о том, что результат записи где-то потребуется и не смог найти упоминания об этом в стандарте.
В вашем случае я могу предположить еще один сценарий, который также сделает вашу программу неработоспособной - компилятор имеет право сделать запись в вашу переменную непосредственно перед выходом из функции. А вы пытаетесь использовать содержимое этой переменной в прерывании до выхода из функции.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Oct 7 2010, 18:19
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



В целом я согласен с Сергей Борщ. Особенно зная его квалификацию. На практике, тем не менее, по крайней мере IAR AVR не выбрасывает массивы в которые идёт запись, но нет чтения. Я использовал такие массивы для отладки.Например, когда мне хотелось просмотреть результаты обработки аналоговых значений в окне watch. Интересно также что массив не выкидывается также и в случае если обращение осуществляется путём работы с указателем.

Думаю, что причина следующая. Массив размещается в принудительном порядке за счёт static, как писал rezident. А обращение к нему не выбрасывается так как на этапе линковки может быть прилинкован модуль ассемблерный или из другого языка, короче тот, где оптимизация затруднена.


PS: Тем не менее не вижу смысла в "хитрых" приёмах, если всё это можно сделать в рамках стандарта. Зачем передавать ссылку на массив размещённый на стэке? Это же ни в какие ворота! Вы этот массив даже в отладчике не увидите сразу после завершения его использования. А ваш указатель формально будет указывать на несуществующие данные. Это для примера.
Надо применять такие приёмы, которые обеспечивают железобетонный результат. А не "от компиляции к компиляции".
Чисто моё мнение конечно.
Go to the top of the page
 
+Quote Post
Itch
сообщение Oct 8 2010, 01:01
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 358
Регистрация: 27-06-06
Из: Новосибирск
Пользователь №: 18 410



Цитата(SasaVitebsk @ Oct 8 2010, 01:19) *
На практике, тем не менее, по крайней мере IAR AVR не выбрасывает массивы в которые идёт запись, но нет чтения. Я использовал такие массивы для отладки.Например, когда мне хотелось просмотреть результаты обработки аналоговых значений в окне watch. Интересно также что массив не выкидывается также и в случае если обращение осуществляется путём работы с указателем.

это смотря как накрутить ему уровень оптимизации. в режиме отладки обычно оптимизацию вообще отключают, тогда все переменные считаются как volatile.
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 8 2010, 09:46
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Ну раз пошла такая пьянка (с привлечением стандартов) то читаем:
Цитата
6.2.4 Storage durations of objects
...
3 An object whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.

Таким образом, выкинуть компилятор ее не может при всем желании, так как Its lifetime is the entire execution of the program

Цитата(Сергей Борщ @ Oct 7 2010, 21:11) *
Ключевой момент - "Если результат такой записи не используется". Т.е. если вы не читате из такой переменной, а только пишете, то такая запись - бесполезная трата тактов процессора. Я не уверен, является ли присвоение адреса переменной указателю сигналом о том, что результат записи где-то потребуется и не смог найти упоминания об этом в стандарте.

А что по-вашему означает "использование" переменной? Как раз присвоение ее значения другой или передача как параметра в функцию. И выкидывать запись в нее компилятор тоже не может, так как это значение может понадобиться функции при последующих входах, она ведь полагается на то, что оно сохранится поскольку Its lifetime is the entire execution of the program.

Цитата(Itch @ Oct 8 2010, 05:01) *
это смотря как накрутить ему уровень оптимизации.

Оптимизация здесь совершенно ни при чем. Поведение static переменных регламентируются стандартом.

Цитата(Itch @ Oct 8 2010, 05:01) *
в режиме отладки обычно оптимизацию вообще отключают

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

ЗЫ. Тут недавно проскакивал пост в котором один такой юзер удивлялся почему AVR-ка не выполняет запись в EEPROM хотя у него все написано правильно:
EECR |= _BV(EEMPE);
EECR |= _BV(EEPE);
правда у него зачем-то оптимизация была отключена в результате для этого кода генерировался десяток команд, а EEMPE действительно лишь на протяжении четырех клоков...


Цитата(SasaVitebsk @ Oct 7 2010, 22:19) *
В целом я согласен с Сергей Борщ. Особенно зная его квалификацию.

Понравилос smile.gif
По таким постам легко отличать верующих от атеистов. Для верующих сила авторитета сильнее стандарта Си. smile.gif
Go to the top of the page
 
+Quote Post
aesok
сообщение Oct 8 2010, 10:02
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(777777 @ Oct 8 2010, 13:46) *
Таким образом, выкинуть компилятор ее не может при всем желании, так как Its lifetime is the entire execution of the program


Проверте сами, может ли компилятор выкинуть static перемную.

Код
void
foo (void)
{
  static int a;
  a = 2;

  return;
}


Скомпилируйте код. Я бы на месте оптимизатора ее выкинул. Или по крайней мере запись в нее.

Анатолий.
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 8 2010, 10:16
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(aesok @ Oct 8 2010, 14:02) *
Проверте сами, может ли компилятор выкинуть static перемную.

Код
#include <avr/io.h>

int main()
{
}

void foo (void)
{
  static int a;
  a = 2;

  return;
}

Даже в этой абсолютно бессмысленной программе он ее не выкидывает:
Код
int main()
    {
    }
  56:    80 e0           ldi    r24, 0x00; 0
  58:    90 e0           ldi    r25, 0x00; 0
  5a:    08 95           ret

0000005c <foo>:

void foo (void)
{
  static int a;
  a = 2;
  5c:    82 e0           ldi    r24, 0x02; 2
  5e:    90 e0           ldi    r25, 0x00; 0
  60:    90 93 01 01     sts    0x0101, r25
  64:    80 93 00 01     sts    0x0100, r24

  return;
}

И даже выполняет в нее запись. Оптимизация -Os
Цитата(aesok @ Oct 8 2010, 14:02) *
Скомпилируйте код. Я бы на месте оптимизатора ее выкинул. Или по крайней мере запись в нее.

Как хорошо, что вы не на месте компилятора! smile.gif
Go to the top of the page
 
+Quote Post
aesok
сообщение Oct 8 2010, 10:22
Сообщение #11


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



ну и еще один пример тогда, конечно с -Os:

Код
#include <avr/io.h>


int main()
{
}

volatile int volatile * p_a;

void foo (void)
{
  static int a;
  
  p_a = &a

  a = 2;


  sei ();
// переменая 'a'  через указатель 'p_a' используется в обработчике прерываня
// и ожидается что ее значение равно 2.
  cli ();

  a = 3;

  return;
}


Анатолий.

Сообщение отредактировал aesok - Oct 8 2010, 10:47
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 8 2010, 11:52
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(aesok @ Oct 8 2010, 16:02) *
Проверте сами, может ли компилятор выкинуть static перемную.


Скомпилируйте код. Я бы на месте оптимизатора ее выкинул. Или по крайней мере запись в нее.
"Не болтайте ерундой!" smile.gif Не может и не должен компилятор выкидывать эту переменную. Она же static, хоть и объявлена внутри функции. Под нее обязательно выделяется ОЗУ и она очищается при стартапе, но область видимости этой переменной - только внутри данной функции. Присвоение значения тоже не выкидывается, т.к. по сути это инициализация ее.
А вот в следующем случае компилятор наверняка оставит только последнее действие.
Код
void foo (void)
{ static int a;
  a = 1;
  a = 2;
  a = 3;
}

И вот в таком случае цикл с проверкой на условие скорее всего заменится на бесконечный цикл. Особенно, если foo1 и foo2 будут в разных единицах (файлах) компиляции.
Код
static unsigned int cntr;

void foo1 (void)
{
    cntr--;
}

void foo2 (void)
{
  cntr=100;
  while (cntr!=0)
    foo1();
}

Go to the top of the page
 
+Quote Post
Petka
сообщение Oct 8 2010, 12:28
Сообщение #13


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(777777 @ Oct 8 2010, 14:16) *
Код
#include <avr/io.h>

int main()
{
}

void foo (void)
{
  static int a;
  a = 2;

  return;
}

Даже в этой абсолютно бессмысленной программе он ее не выкидывает:
......
И даже выполняет в нее запись. Оптимизация -Os

Как хорошо, что вы не на месте компилятора! smile.gif

добавьте ключик "-ffunction-sections -fdata-sections -Wl,--gc-sections" и от вашей статической переменной абсолютно ничего не останется.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Oct 8 2010, 12:46
Сообщение #14


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(777777 @ Oct 8 2010, 12:46) *
Понравилос smile.gif
По таким постам легко отличать верующих от атеистов. Для верующих сила авторитета сильнее стандарта Си. smile.gif
Ну так вот стандрат С говорит, что компилятор в процессе оптимизации обязан обеспечить observable behaviour такое же, как у абстрактной машины языка. Да, время жизни static-переменной по стандарту совпадает с временем жизни программы. Но и время жизни static-функции совпадает с ним же. А компилятор успешно выбрасывает, если она в пределах этого же файла не вызывается сама и её адрес никуда не передаётся. А всё почему - на всё то же o.b. не виляет - выбрасываем.

Так что наличие обсуждаемой static-переменной в функции foo() с observable behaviour никак не связано, поэтому компилятор имеет право её выбросить. Всё зависит от уровня оптимизации, на который способен компилятор и от указаний ему по этому поводу.
Код
#include <avr/io.h>

void
foo (void)
{
    static int a;
    a = 2;
    return;
}


void
main(void)
{
    for(;;) {
        foo();
        PORTB ^= 0x01;
    }
}

avr-gcc -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -mmcu=atmega8 static.c
avr-objdump -d a.out >static.dump
Код
  ...
0000005e <main>:
  5e:    91 e0           ldi    r25, 0x01; 1
  60:    88 b3           in    r24, 0x18; 24
  62:    89 27           eor    r24, r25
  64:    88 bb           out    0x18, r24; 24
  66:    fc cf           rjmp    .-8     ; 0x60 <main+0x2>
  ...


Или так
avr-gcc -Os -fwhole-program -S -mmcu=atmega8 static.c
Код
.global    main
    .type    main, @function
main:
/* prologue: function */
/* frame size = 0 */
    ldi r25,lo8(1)
.L2:
    in r24,56-32
    eor r24,r25
    out 56-32,r24
    rjmp .L2


А то, что не выкинул при компиляции одной только функции foo() - ну так есть ещё над чем работать. Поскольку переменная не volatile, внутри функци не считывается и её адрес никуда не передаётся — она может быть выброшена. Не в этой версии компилятора, так в следующей.

С массивами, в которые из основного кода ведётся только запись, а из прерывания — только чтение, тоже не всё так просто. Если массив не volatile, то компилятор имеет право переставить запись в него и взведение volatile-флага, информирующего прерывание о том, что запись произведена. В результате прерывание может начать читать буфер до того, как в него реально произведена запись.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 8 2010, 13:46
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(rezident @ Oct 8 2010, 14:52) *
Она же static, хоть и объявлена внутри функции.
Да и хрен на нее, хоть и static. На то и оптимизатор. Пользы от переменной никакой, накой ее держать?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 18:49
Рейтинг@Mail.ru


Страница сгенерированна за 0.01537 секунд с 7
ELECTRONIX ©2004-2016