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

 
 
> Использование 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
 
Start new topic
Ответов
Сергей Борщ
сообщение Oct 7 2010, 17:11
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 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
777777
сообщение Oct 8 2010, 09:46
Сообщение #3


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

Группа: Участник
Сообщений: 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
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 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
Сообщение #5


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

Группа: Участник
Сообщений: 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
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 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
aesok
сообщение Oct 9 2010, 22:02
Сообщение #7


Знающий
****

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



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

extern void foo (void);
volatile int volatile * p_a;

int main()
{
  foo ();
  foo ();

  return 0;
}

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

  p_a = &a;

  a = 2;

  cli ();

  // предположим что в этот момент управление
  // передаеться обработчику прерывания и в нем
  // происходит чтение локальной переменной 'a'
  // через указарель 'p_a'.

  sei ();
  
  a = 3;
  return;
}


Вопрос: Какое значение получает обработчик прерывания через указарель 'p_a', если код скомпилирован с -Os? Кто считает что 2?


Код
.global    foo
    .type    foo, @function
foo:
    ldi r24,lo8(a.1233)
    ldi r25,hi8(a.1233)
    sts p_a+1,r25
    sts p_a,r24
/* #APP */
;  23 "main.c" 1
    cli
;  0 "" 2
;  30 "main.c" 1
    sei
;  0 "" 2
/* #NOAPP */
    ldi r24,lo8(3)
    ldi r25,hi8(3)
    sts a.1233+1,r25
    sts a.1233,r24
    ret
    .size    foo, .-foo
.global    main
    .type    main, @function
main:
    rcall foo
    rcall foo
    ldi r24,lo8(0)
    ldi r25,hi8(0)
    ret
    .size    main, .-main
    .comm p_a,2,1
    .data
    .type    a.1233, @object
    .size    a.1233, 2
a.1233:
    .word    1


Правильный ответ: при первом вызове foo () 1, при последующих 3.

Анатолий.

Сообщение отредактировал aesok - Oct 9 2010, 22:02
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 10 2010, 08:57
Сообщение #8


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

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



Цитата(aesok @ Oct 10 2010, 02:02) *
Правильный ответ: при первом вызове foo () 1, при последующих 3.

Разумеется, потому что с точки зрения компилятора у тебя идут две подряд строки
a = 2;
a = 3;
Результат выполнения этой программы - занесения 3 в переменную a. Но это последнее присваивание компилятор не имеет права выбрасывать потому что a - static! И этот результат может понадобиться при последующих вызовах этой функции.

В моем случае последовательность была такая:
Код
    uint8_t cmd[3] = { 8, mn, 0 };

    pTWI = cmd;
    SendSLA();

Здесь компилятор не имеет права выбрасывать ничего, даже если бы pTWI было не volatile потому что:
а) адрес cmd присваивается глобальной переменной, сделовательно cmd используется и он должен быть инициализирован;
б) pTWI - глобальная переменная, следовательно она может использоваться в других функциях, а значит по выходу из функции в ней должен быть адрес cmd;
в) более того, следом вызывается некая глобальная функция, поэтому компилятор обязан предположить, что pTWI может использоваться в этой функции, следовательно адрес cmd должен быть присвое ей до вызова SendSLA
После того как я сделал массив static ограничений стало еще больше.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Oct 10 2010, 12:31
Сообщение #9


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(777777 @ Oct 10 2010, 12:57) *
Разумеется...
...последнее присваивание компилятор не имеет права выбрасывать потому что a - static!
Вы не правы. Привязались к статику уак банный лист:-)
Он не для этого задуман. И все ваши домыслы можно поставить с ног на голову путём изменения опций компилятора и линкера.
Остыньте и сделайте два-три глубоких вдоха. В этом споре вы уже проиграли. Сэ ля виsad.gif

PS
aesok, с возвращением!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 11 2010, 04:30
Сообщение #10


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

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



Цитата(demiurg_spb @ Oct 10 2010, 16:31) *
Вы не правы. Привязались к статику уак банный лист:-)
Он не для этого задуман. И все ваши домыслы можно поставить с ног на голову путём изменения опций компилятора и линкера.
Остыньте и сделайте два-три глубоких вдоха. В этом споре вы уже проиграли.

А для чего же он создан? Приведите раздел стандарта который это объясняет. В крайнем случае, приведите пример программы с набором опций компилятора и линкера. Вы ничего этого не сделали, но почему-то объявляете, что я проиграл.

Статик создан именно для того, чтобы его значение, установленное в функции, сохранялось при выходе из нее и было таким же при повторном входе в эту функцию. Компилятор имеет большую свободу действий, но такое поведение переменной он обязан обеспечивать. Если у вас есть другие мнения на этот счет - объясните, желательно с убедительной аргументацией.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Oct 11 2010, 04:41
Сообщение #11


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(777777 @ Oct 11 2010, 09:30) *
Статик создан именно для того, чтобы его значение, установленное в функции, сохранялось при выходе из нее и было таким же при повторном входе в эту функцию.

Это такая же голимая интерпретация как и я писал об volatille smile.gif
Я хотя бы для себя ввёл то правило, являющееся следствием оптимизации компиляторов. То есть "моё" правило, напрямую не касалось определения volatille, а просто юзало его.

Статик просто размещает переменную в каком-то там сегменте (bss или др.). И всё. Остальное на совести компилятора.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 11 2010, 07:36
Сообщение #12


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

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



Цитата(GetSmart @ Oct 11 2010, 08:41) *
Статик просто размещает переменную в каком-то там сегменте (bss или др.). И всё. Остальное на совести компилятора.

Что именно "всё остальное"? Стандарт четко определяет время жизни (lifetime) переменной. Что по-вашему означает этот термин?

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

Вы даете компилятору слишком много воли. Если бы это было так, то программы было бы невозможно писать. Наслушавшись таких разговоров некоторые предпочитают асм, думая, что компилятор действительно может сгенерировать не то, что написал программист. Но к счастью это не так.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- 777777   Использование static переменных   Oct 7 2010, 15:41
- - rezident   Не совсем понятно из какого топика вырвана эта цит...   Oct 7 2010, 16:14
|- - 777777   Цитата(rezident @ Oct 7 2010, 20:14) Не с...   Oct 7 2010, 16:32
|- - rezident   Цитата(777777 @ Oct 7 2010, 22:32) И обра...   Oct 7 2010, 16:43
|||- - demiurg_spb   Цитата(777777 @ Oct 11 2010, 08:30) А для...   Oct 11 2010, 08:58
||||- - 777777   Цитата(demiurg_spb @ Oct 11 2010, 12:58) ...   Oct 11 2010, 10:20
||||- - demiurg_spb   Цитата(777777 @ Oct 11 2010, 14:20) Ну, е...   Oct 11 2010, 12:49
|||- - halfdoom   Цитата(777777 @ Oct 11 2010, 07:30) Стати...   Oct 11 2010, 10:52
|||- - GetSmart   Цитата(halfdoom @ Oct 11 2010, 15:52) Ори...   Oct 11 2010, 10:58
|||- - 777777   Цитата(halfdoom @ Oct 11 2010, 14:52) Ори...   Oct 11 2010, 11:10
|||- - halfdoom   Цитата(777777 @ Oct 11 2010, 14:10) Ключе...   Oct 11 2010, 11:18
|||- - GetSmart   Цитата(777777 @ Oct 11 2010, 16:10) ... П...   Oct 11 2010, 11:25
||- - Petka   Цитата(777777 @ Oct 8 2010, 14:16) Код#in...   Oct 8 2010, 12:28
|- - ReAl   Цитата(777777 @ Oct 8 2010, 12:46) Понрав...   Oct 8 2010, 12:46
|- - SasaVitebsk   Цитата(777777 @ Oct 8 2010, 12:46) Понрав...   Oct 8 2010, 23:03
- - SasaVitebsk   В целом я согласен с Сергей Борщ. Особенно зная ег...   Oct 7 2010, 18:19
|- - Itch   Цитата(SasaVitebsk @ Oct 8 2010, 01:19) Н...   Oct 8 2010, 01:01
- - rezident   Цитата(aesok @ Oct 8 2010, 16:02) Проверт...   Oct 8 2010, 11:52
|- - Сергей Борщ   Цитата(rezident @ Oct 8 2010, 14:52) Она ...   Oct 8 2010, 13:46
|- - rezident   Цитата(Сергей Борщ @ Oct 8 2010, 19:46) Д...   Oct 8 2010, 13:54
|- - Petka   Цитата(rezident @ Oct 8 2010, 17:54) Не е...   Oct 8 2010, 14:10
||- - rezident   Цитата(Petka @ Oct 8 2010, 20:10) На любо...   Oct 8 2010, 15:01
||- - MALLOY2   Не зряж в IAR введен Extended keyword __root с пом...   Oct 8 2010, 15:21
|- - Oldring   Цитата(rezident @ Oct 8 2010, 17:54) Не е...   Oct 8 2010, 14:51
|- - MrYuran   Цитата(rezident @ Oct 8 2010, 17:54) Не е...   Oct 11 2010, 08:10
- - GetSmart   Чтобы прерывания правильно обрабатывали глобальные...   Oct 9 2010, 22:17
|- - aesok   Цитата(GetSmart @ Oct 10 2010, 02:17) Что...   Oct 9 2010, 22:32
|- - 777777   Цитата(GetSmart @ Oct 10 2010, 02:17) Что...   Oct 10 2010, 10:03
|- - _Pasha   Цитата(777777 @ Oct 10 2010, 14:03) компи...   Oct 10 2010, 12:07
- - GetSmart   Я уже потерял суть спора. Чё не нравится? В смысле...   Oct 11 2010, 07:55


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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 04:44
Рейтинг@Mail.ru


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