const 1 25 августа Опубликовано 25 августа · Жалоба 2 minutes ago, jcxz said: Код то тот, но в проекте IAR ТС-а могут быть и другие файлы (они должны быть - ведь у нас МК, где-то есть инициализация его периферии). в моем примере только такие файлы: 1. startup_stm32f4xx.s 2. system_stm32f4xx.c 3. main.c (весь код которого приведен) 4. foo.c (с одной лишь ф-цей foo) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба 44 минуты назад, jcxz сказал: Ошибаетесь. Какой-то код мог быть выполнен и до main(). Например - запущен ISR или вообще - запущена ОС. Задачи которой и могут модифицировать glb уже после её инициализации. Пускай даже она без volatile. Это проблемы того, кто это пишет. Компилятор должен соответствовать правилам языка, а они вполне конкретны. Си ничего не знает ни об ISR, ни о задачах ОС, вызванных до main(). Поэтому может смело полагаться (если нет других ограничивающих факторов) на то, что в этой переменной будет именно 0, а не что-то другое, и тут же выполнить оптимизацию - в данном случае, выкинув весь код. Цитата Код то тот, но в проекте IAR ТС-а могут быть и другие файлы (они должны быть - ведь у нас МК, где-то есть инициализация его периферии). И IAR их имел в виду. А вы в тесте взяли ровно только то, что написано в исходном сообщении. Какое мне дело до того, что у ТС еще в проекте, если он привел вполне самодостаточный кусок кода, который я смог вставить в свой проект и скомпилировать? Я вставил ровно то, что он привел, и определил функцию foo() в другом сишнике, в ее теле сделал доступ к volatile, чтобы функция не выкинулась. Результат я написал - после входа в main() получил пустой зацикленный код. И да - у меня в этом тестовом проекте тоже много файлов, и до main() тоже кое-чего вызывается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
const 1 25 августа Опубликовано 25 августа · Жалоба 6 minutes ago, Arlleex said: Результат я написал - после входа в main() получил пустой зацикленный код. после добавления роботы с портами у вас "пустой зацикленный код" остался? Или все же не пустой цикл? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба 3 минуты назад, const сказал: после добавления роботы с портами у вас "пустой зацикленный код" остался? Или все же не пустой цикл? Работы с портами конкретно где? Перед циклом в main() или в функции foo()? При добавлении glb = GPIOA->IDR перед вызовом tst() в цикле main() код уже, конечно же, не выкинулся. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
const 1 25 августа Опубликовано 25 августа (изменено) · Жалоба 3 minutes ago, Arlleex said: Работы с портами конкретно где? Перед циклом в main() или в функции foo()? вот так https://electronix.ru/forum/topic/192075-pri-maksimalnoy-optimizatsii-oshibka/?do=findComment&comment=1944224 Изменено 25 августа пользователем const Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба Выше пост дополнил. Не выкинул. P.S. Более того, если в случае, когда код полностью выкидывался, переменную glb объявить с атрибутом размещения в неинициализируемой области, оптимизатор так же не выкинет код (потому что в этом случае он уже действительно не может полагаться на инициализацию 0 при входе в main()) uint8_t glb __attribute__((section(".bss.uninitSection"), used)); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 25 августа Опубликовано 25 августа · Жалоба 41 минуту назад, Arlleex сказал: Это проблемы того, кто это пишет. Компилятор должен соответствовать правилам языка, а они вполне конкретны. Си ничего не знает ни об ISR, ни о задачах ОС, вызванных до main(). Если он должен соответствовать, тогда он должен увидеть, что glb - глобальная переменная. А значит - может быть модифицирована за пределами данной единицы компиляции (файла). А значит - он не имеет права удалять её использование. У вас же - удалил. 41 минуту назад, Arlleex сказал: Какое мне дело до того, что у ТС еще в проекте, если он привел вполне самодостаточный кусок кода, который я смог вставить в свой проект и скомпилировать? Вот именно. Ключевое слово: вставил в свой проект. А ТС компилил в своём проекте, а не в вашем. А там у него были и другие файлы. И другой стартап-код. Чего вы не учли в своём тесте. Потому и пишу, что ваш тест скорее всего некорректный. 41 минуту назад, Arlleex сказал: Я вставил ровно то, что он привел, и определил функцию foo() в другом сишнике, в ее теле сделал доступ к volatile, чтобы функция не выкинулась. Результат я написал - после входа в main() получил пустой зацикленный код. И да - у меня в этом тестовом проекте тоже много файлов, и до main() тоже кое-чего вызывается. У вас в вашем проекте нигде нет обращений к glb. И вы сказали компилятору (видимо) - или сделать link-time оптимизацию или он сам её сделал. Другими словами - есть исходник, в нём есть глобальный объект. Мы делаем компиляцию исходника. В результате компиляции мы что должны получить? Правильно - объектный файл. Именно объектный файл, а не исполняемый образ. Этот объектный файл потом может быть включен в другой проект. А в том другом проекте может или быть или не быть обращения к glb. А значит - скомпилировав исходник так, что glb была вообще удалена, вы сделали ошибку. Потому как ваш объектный файл, при последующем включении в проект где используется glb, не будет правильно линковаться (возможно - вообще не будет линковаться). Для корректного теста примера ТС, вы должны были запретить оптимизацию компоновщика. Так как не знаете всех компонентов проекта ТС. Вот тогда тест был бы корректный. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба 2 минуты назад, jcxz сказал: Если он должен соответствовать, тогда он должен увидеть, что glb - глобальная переменная. А значит - может быть модифицирована за пределами данной единицы компиляции (файла). А значит - он не имеет права удалять её использование. У вас же - удалил. Вот именно. Ключевое слово: вставил в свой проект. А ТС компилил в своём проекте, а не в вашем. А там у него были и другие файлы. И другой стартап-код. Чего вы не учли в своём тесте. Потому и пишу, что ваш тест скорее всего некорректный. У вас в вашем проекте нигде нет обращений к glb. И вы сказали компилятору (видимо) - или сделать link-time оптимизацию или он сам её сделал. Другими словами - есть исходник, в нём есть глобальный объект. Мы делаем компиляцию исходника. В результате компиляции мы что должны получить? Правильно - объектный файл. Именно объектный файл, а не исполняемый образ. Этот объектный файл потом может быть включен в другой проект. А в том другом проекте может или быть или не быть обращения к glb. А значит - скомпилировав исходник так, что glb была вообще удалена, вы сделали ошибку. Потому как ваш объектный файл, при последующем включении в проект где используется glb, не будет правильно линковаться (возможно - вообще не будет линковаться). Для корректного теста примера ТС, вы должны были запретить оптимизацию компоновщика. Так как не знаете всех компонентов проекта ТС. Вот тогда тест был бы корректный. Я же вроде написал, что у меня при включенной LTO удаляется. При выключенной - нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 25 августа Опубликовано 25 августа · Жалоба 27 минут назад, Arlleex сказал: (потому что в этом случае он уже действительно не может полагаться на инициализацию 0 при входе в main()) Компилятор в любом случае не может полагаться "на инициализацию 0 при входе в main())". Не понимаю почему вы так думаете. С чего он должен полагаться что glb==0 на входе в main()? Это не так. Я выше уже писал - почему. Только что, Arlleex сказал: Я же вроде написал, что у меня при включенной LTO удаляется. При выключенной - нет. А ну вот. Не заметил значит. Тест с включенной LTO - не корректный. 45 минут назад, Arlleex сказал: Поэтому может смело полагаться (если нет других ограничивающих факторов) на то, что в этой переменной будет именно 0 нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
const 1 25 августа Опубликовано 25 августа · Жалоба 2 minutes ago, jcxz said: Компилятор в любом случае не может полагаться "на инициализацию 0 при входе в main())". Не понимаю почему вы так думаете. С чего он должен полагаться что glb==0 на входе в main()? Это не так. Я выше уже писал - почему. Если я не ошибаюсь, в С++ глобальные переменные по умолчанию static, если не указано иного (extern напр.), может в этом дело. Тогда действительно, компилятор видит, что в данной единице компиляции объект не используется и выкидывает его. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба 6 минут назад, jcxz сказал: Компилятор в любом случае не может полагаться "на инициализацию 0 при входе в main())". Не понимаю почему вы так думаете. С чего он должен полагаться что glb==0 на входе в main()? В стандарте так написано, потому что. Для примера, из C11 Цитата 10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then: — if it has pointer type, it is initialized to a null pointer; — if it has arithmetic type, it is initialized to (positive or unsigned) zero; — if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; — if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; Это требование обязан соблюдать компилятор при генерации кода. А значит, может смело на это полагаться. 1 минуту назад, const сказал: Если я не ошибаюсь, в С++ глобальные переменные по умолчанию static, если не указано иного (extern напр.), может в этом дело. Тогда действительно, компилятор видит, что в данной единице компиляции объект не используется и выкидывает его. Так у Вас Си или C++? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
const 1 25 августа Опубликовано 25 августа · Жалоба 1 minute ago, Arlleex said: Так у Вас Си или C++? Си, а у вас? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба И у меня Си. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 25 августа Опубликовано 25 августа · Жалоба Инициализация glb выполняется си-startup-кодом, а не самой main(). си-startup - это отдельная функция. Соответственно - файл с main() может скомпилирован, а потом вставлен как .obj в другой проект. А в том другом проекте в си-startup-коде например вызывается какой-то конструктор глобального объекта. Внутри которого стартует периодический ISR. И этот ISR модифицирет ISR. И модифицирует он её в момент между си-startup и входом в main(). Может такое быть? Да, может. Да, так как glb - не volatile, то компилятор имеет полное право создать её копию в той единице компиляции, в которой она используется. Например - внутри main() в регистре. Но не ранее! А ISR может между си-startup и входом в main() записать в glb что-то отличное от нуля. Вот в этом случае на входе в main() копия glb в регистре будет создана нормально. И будет она содержать !=0. А значит ваш результат компиляции, в котором использование glb вообще удалено - некорректный. 7 минут назад, Arlleex сказал: 13 минут назад, jcxz сказал: Компилятор в любом случае не может полагаться "на инициализацию 0 при входе в main())". Не понимаю почему вы так думаете. С чего он должен полагаться что glb==0 на входе в main()? В стандарте так написано, потому что. Для примера, из C11 Ну значит - IAR вообще не соответствует стандарту. Так как у него - си-startup и main() - разные функции. Между которыми может быть прерывание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 187 25 августа Опубликовано 25 августа · Жалоба 7 минут назад, jcxz сказал: Ну значит - IAR вообще не соответствует стандарту. Так как у него - си-startup и main() - разные функции. Между которыми может быть прерывание. Я понимаю, о чем Вы пишете. Но повторюсь - Си предполагает, что на момент входа в main() состояние среды будет вполне детерминированным - т.е. глобальные статические переменные без явной инициализации или атрибутов для других инструментов (например, компоновщика) будут иметь значение 0. В приведенном ТС коде нет никаких сведений о явной инициализации или доп. атрибутах. Значит компилятор может смело полагаться, что при входе в main() в glb будет лежать 0. Хоть там три километра кода было до вызова main(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться