777777 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Оптимизатор вполне может выкинуть запись в любую переменную, будь то обычный int или массив, если он видит, что результат такой записи не используется (а с его точки зрения он не используется). Насчет любой переменной вы погорячились - значения static переменных сохраняются даже после выхода из функции и будут иметь его при повторном входе в эту функцию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Не совсем понятно из какого топика вырвана эта цитата, но вы исказили ее смысл, попустив слово "запись". По смыслу у Сергея Борща "выкинуть" не саму переменную, а выкинуть обращение к ней. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
777777 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Не совсем понятно из какого топика вырвана эта цитата, Отсюда. Модераторы мудро решили ее закрыть. но вы исказили ее смысл, попустив слово "запись". Я не пропустил слово "запись" По смыслу у Сергея Борща "выкинуть" не саму переменную, а выкинуть обращение к ней. И обращение к ней (запись в нее) он не может выкинуть, так как должен знать, что результат может понадобиться при следующем обращении к ней. Если она static. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба И обращение к ней (запись в нее) он не может выкинуть, так как должен знать, что результат может понадобиться при следующем обращении к ней. Если она static. static относится к storage-class specifier, т.е. влияет лишь на размещение и область видимости объекта, но не влияет на оптимизацию обращения к данному объекту. Для предотвращения оптимизации обращения к объекту применяется квалификатор volatile, который наряду с const и restrict относится к квалификаторам типа (type qualifiers). См. стандарт C99 (ISO/IEC 9899:1999).C99_iso_iec_9899_1999.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Насчет любой переменной вы погорячились - значения static переменных сохраняются даже после выхода из функции и будут иметь его при повторном входе в эту функцию.Ключевой момент - "Если результат такой записи не используется". Т.е. если вы не читате из такой переменной, а только пишете, то такая запись - бесполезная трата тактов процессора. Я не уверен, является ли присвоение адреса переменной указателю сигналом о том, что результат записи где-то потребуется и не смог найти упоминания об этом в стандарте. В вашем случае я могу предположить еще один сценарий, который также сделает вашу программу неработоспособной - компилятор имеет право сделать запись в вашу переменную непосредственно перед выходом из функции. А вы пытаетесь использовать содержимое этой переменной в прерывании до выхода из функции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба В целом я согласен с Сергей Борщ. Особенно зная его квалификацию. На практике, тем не менее, по крайней мере IAR AVR не выбрасывает массивы в которые идёт запись, но нет чтения. Я использовал такие массивы для отладки.Например, когда мне хотелось просмотреть результаты обработки аналоговых значений в окне watch. Интересно также что массив не выкидывается также и в случае если обращение осуществляется путём работы с указателем. Думаю, что причина следующая. Массив размещается в принудительном порядке за счёт static, как писал rezident. А обращение к нему не выбрасывается так как на этапе линковки может быть прилинкован модуль ассемблерный или из другого языка, короче тот, где оптимизация затруднена. PS: Тем не менее не вижу смысла в "хитрых" приёмах, если всё это можно сделать в рамках стандарта. Зачем передавать ссылку на массив размещённый на стэке? Это же ни в какие ворота! Вы этот массив даже в отладчике не увидите сразу после завершения его использования. А ваш указатель формально будет указывать на несуществующие данные. Это для примера. Надо применять такие приёмы, которые обеспечивают железобетонный результат. А не "от компиляции к компиляции". Чисто моё мнение конечно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Itch 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба На практике, тем не менее, по крайней мере IAR AVR не выбрасывает массивы в которые идёт запись, но нет чтения. Я использовал такие массивы для отладки.Например, когда мне хотелось просмотреть результаты обработки аналоговых значений в окне watch. Интересно также что массив не выкидывается также и в случае если обращение осуществляется путём работы с указателем. это смотря как накрутить ему уровень оптимизации. в режиме отладки обычно оптимизацию вообще отключают, тогда все переменные считаются как volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
777777 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Ну раз пошла такая пьянка (с привлечением стандартов) то читаем: 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 Ключевой момент - "Если результат такой записи не используется". Т.е. если вы не читате из такой переменной, а только пишете, то такая запись - бесполезная трата тактов процессора. Я не уверен, является ли присвоение адреса переменной указателю сигналом о том, что результат записи где-то потребуется и не смог найти упоминания об этом в стандарте. А что по-вашему означает "использование" переменной? Как раз присвоение ее значения другой или передача как параметра в функцию. И выкидывать запись в нее компилятор тоже не может, так как это значение может понадобиться функции при последующих входах, она ведь полагается на то, что оно сохранится поскольку Its lifetime is the entire execution of the program. это смотря как накрутить ему уровень оптимизации. Оптимизация здесь совершенно ни при чем. Поведение static переменных регламентируются стандартом. в режиме отладки обычно оптимизацию вообще отключают Оптимизацию отключают только... альтернативно одаренные люди. Мне кажется что сама возможность ее отключения оставлена для того, чтобы пользователь мог отключив ее убедиться что виноват не оптимизатор, а его программа. ЗЫ. Тут недавно проскакивал пост в котором один такой юзер удивлялся почему AVR-ка не выполняет запись в EEPROM хотя у него все написано правильно: EECR |= _BV(EEMPE); EECR |= _BV(EEPE); правда у него зачем-то оптимизация была отключена в результате для этого кода генерировался десяток команд, а EEMPE действительно лишь на протяжении четырех клоков... В целом я согласен с Сергей Борщ. Особенно зная его квалификацию. Понравилос :) По таким постам легко отличать верующих от атеистов. Для верующих сила авторитета сильнее стандарта Си. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aesok 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Таким образом, выкинуть компилятор ее не может при всем желании, так как Its lifetime is the entire execution of the program Проверте сами, может ли компилятор выкинуть static перемную. void foo (void) { static int a; a = 2; return; } Скомпилируйте код. Я бы на месте оптимизатора ее выкинул. Или по крайней мере запись в нее. Анатолий. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
777777 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Проверте сами, может ли компилятор выкинуть 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 0 8 октября, 2010 Опубликовано 8 октября, 2010 (изменено) · Жалоба ну и еще один пример тогда, конечно с -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; } Анатолий. Изменено 8 октября, 2010 пользователем aesok Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Проверте сами, может ли компилятор выкинуть static перемную. Скомпилируйте код. Я бы на месте оптимизатора ее выкинул. Или по крайней мере запись в нее. "Не болтайте ерундой!" :) Не может и не должен компилятор выкидывать эту переменную. Она же 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(); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Petka 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба #include <avr/io.h> int main() { } void foo (void) { static int a; a = 2; return; } Даже в этой абсолютно бессмысленной программе он ее не выкидывает: ...... И даже выполняет в нее запись. Оптимизация -Os Как хорошо, что вы не на месте компилятора! :) добавьте ключик "-ffunction-sections -fdata-sections -Wl,--gc-sections" и от вашей статической переменной абсолютно ничего не останется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Понравилос :) По таким постам легко отличать верующих от атеистов. Для верующих сила авторитета сильнее стандарта Си. :) Ну так вот стандрат С говорит, что компилятор в процессе оптимизации обязан обеспечить 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-флага, информирующего прерывание о том, что запись произведена. В результате прерывание может начать читать буфер до того, как в него реально произведена запись. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Она же static, хоть и объявлена внутри функции.Да и хрен на нее, хоть и static. На то и оптимизатор. Пользы от переменной никакой, накой ее держать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться