Как избавиться от глобальных переменных в многофайловом проекте на С++?
Некоторые глобальные переменные можно заменить на глобальные константы. Долго промучилась с проектом, но на попытках избавления от глобальеных переменных отказывали те или иные функции. Проект представляет собой игру крестики-нолики против человека и компьютера.
Проект10.zip
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Графический интерфейс НЕ GUI! как избавиться от глобальных переменных?
Создаю простенький графический интерфейс function = interface( input_args ) global hAxes.
Объявление глобальных переменных в проекте Dev C++
Доброй ночи всем! Подскажите, пожалуйста, как правильно объявить глобальные переменные в проекте.

Как в многофайловом проекте сделать глобальную переменную?
имеется проект из 100500 файлов: main.cpp — тело программы, и прочие *.h и *.cpp файлы. в main’е.
447 / 261 / 89
Регистрация: 11.11.2014
Сообщений: 916
EnjiRouz, вообще совет попробуйте передавать те переменные, которые объявлены как глобальные переменные, аргументами функции, допустим поле через указатель и т.д. потому что у вас сейчас в коде очень сильная связность, если просто удалить переменную или поменять ее имя, то половину функций менять, аргументы чуть чуть, но уже избавят от этого
Добавлено через 4 минуты
EnjiRouz, потом к примеру функция бот, которая вызывает функцию bot_checking, тоже завязывает бота на выполнение одной стратегии, сделайте его более гибким, допустим не в тупую вызывайте bot_checking, а передавайте указатель на функцию которая принимает решение на выбор хода, потом про сам выбор, рандом это ну мягко говоря плохо, поэтому давайте гуглите что такое минимакс алгортим
Добавлено через 5 минут
также практика забивать выйгрышные варианты, представьте ситуацию, что у вас поле не 3х3 а 10х10, но побеждает тот кто сделает первые 3 по горизонтали, вертикали или диагонали, будет очень сложно описать все руками, поэтому тоже совет, сделайте это алгоритмом
Добавлено через 2 минуты
EnjiRouz, ну и мелкие ошибки в коде, например
1 2 3 4 5 6 7 8 9
if (s == '+') { system("cls"); return true; } else { return false;; }
в функции рестарт можно вот так записать
1 2 3 4 5 6
if (s == '+') { system("cls"); return true; } return false;;
Добавлено через 1 минуту
тоже самое в функции no_winner, бесполезный ретерн в get_winner, не подумайте что придераюсь, просто это нагружает код и его тяжелее читать
Добавлено через 51 секунду
вообще во всех функция void не нужно в конце писать return
Как избавиться от глобальных переменных c
Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
Re: как можно избавиться от глобальных переменных ?
| От: | LuciferMoscow |
| Дата: | 22.03.05 09:18 |
| Оценка: |
Здравствуйте, Аноним,
1. Статические члены класса
2. В более сложной ситуации «Синглетоны»
Re: как можно избавиться от глобальных переменных ?
| От: | BlackHeretic |
| Дата: | 22.03.05 09:20 |
| Оценка: |
Здравствуйте, Аноним, Вы писали:
А>Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
А>вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
Не понял. Библиотека использует прогу.
ICQ 156156278
Re: как можно избавиться от глобальных переменных ?
| От: | MaximE |
| Дата: | 22.03.05 09:45 |
| Оценка: |
wrote:
> Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
>
> вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
Складываешь свои глобальные переменные в структуру, в вызовах передаешь указатель на эту стр-ру.
int a, b; void foo() < a += b; >void bar()
struct context < int a, b; >; void foo(context* ctx) < ctx->a += ctx->b; > void bar(context* ctx) < ctx->b += ctx->a; >
—
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[2]: как можно избавиться от глобальных переменных ?
| От: | Аноним |
| Дата: | 22.03.05 09:46 |
| Оценка: |
Здравствуйте, BlackHeretic, Вы писали:
BH>Здравствуйте, Аноним, Вы писали:
А>>Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
А>>вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
BH>Не понял. Библиотека использует прогу.
нет конечно же ! 8) я неправельно выразился просто
Re[3]: как можно избавиться от глобальных переменных ?
| От: | BlackHeretic |
| Дата: | 22.03.05 09:50 |
| Оценка: |
Здравствуйте, Аноним, Вы писали:
А>нет конечно же ! 8) я неправельно выразился просто
Тогда могу предложить синглтон для этих переменных.
В хедер файле что-то типа
struct MyCommon < int& A() < static int a = 0; return a; > wstring& Name() < static int name = L"booo"; return name; > >;
В общем идея надеюсь понятна — реализация конечно не супер, но тут уж кто как хочет так и пишет
ICQ 156156278
Re: как можно избавиться от глобальных переменных ?
| От: | Аноним |
| Дата: | 22.03.05 10:06 |
| Оценка: |
Здравствуйте, Аноним, Вы писали:
А>Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
А>вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
Проще и быстрее всего наверное сделать их статическими членами класса
int g_nValue; char* g_szString;
struct Data < int nValue; char* szString; >;
Re[2]: как можно избавиться от глобальных переменных ?
| От: | Аноним |
| Дата: | 22.03.05 10:19 |
| Оценка: |
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
А>>вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
А>Проще и быстрее всего наверное сделать их статическими членами класса
struct Data < static int nValue; static char* szString; >;
Re: как можно избавиться от глобальных переменных ?
| От: | BacCM |
| Дата: | 22.03.05 13:28 |
| Оценка: |
Здравствуйте, <Аноним>, Вы писали:
А>Вобщем у меня есть библиотека и прога которую она использует и есть несколько переменных которые для них «общие». От этого момента желательно было бы избавиться, но я ничего лучше, чем заменить переменнные на указатели придумать не могу. А использовать какие-то фиксированные адреса — достатточно рискованно.
А>вобщем если кто сталкивался с чем-то подобным и может подсказать как ещё можно обойти глобальные переменные не потеряв связь библиотеки и проги.
Аноним>
ИМХО если библиотека функций то обернуть доступ к переменным функциями, притом не обязательно прямыми типа set и get, а более подходящими к библиотеки: InitSuperLibrary, ChangeMode.
Локальные и глобальные переменные
В программировании особое внимание уделяется концепции о локальных и глобальных переменных, а также связанное с ними представление об областях видимости. Соответственно, локальные переменные видны только в локальной области видимости, которой может выступать отдельно взятая функция. Глобальные переменные видны во всей программе. «Видны» – значит, известны, доступны. К ним можно обратиться по имени и получить связанное с ними значение.
К глобальной переменной можно обратиться из локальной области видимости. К локальной переменной нельзя обратиться из глобальной области видимости, потому что локальная переменная существует только в момент выполнения тела функции. При выходе из нее, локальные переменные исчезают. Компьютерная память, которая под них отводилась, освобождается. Когда функция будет снова вызвана, локальные переменные будут созданы заново.
Вернемся к нашей программе из прошлого урока, немного упростив ее для удобства:
def rectangle(): a = float(input("Ширина: ")) b = float(input("Высота: ")) print("Площадь: %.2f" % (a * b)) def triangle(): a = float(input("Основание: ")) h = float(input("Высота: ")) print("Площадь: %.2f" % (0.5 * a * h)) figure = input("1-прямоугольник, 2-треугольник: ") if figure == '1': rectangle() elif figure == '2': triangle()
Сколько здесь переменных? Какие из них являются глобальными, а какие – локальными?
Здесь пять переменных. Глобальной является только figure . Переменные a и b из функции rectangle , а также a и h из triangle – локальные. При этом локальные переменные с одним и тем же идентификатором a , но объявленные в разных функциях, – разные переменные.
Следует отметить, что идентификаторы rectangle и triangle , хотя и не являются именами переменных, а представляют собой имена функций, также имеют область видимости. В данном случае она глобальная, так как функции объявлены непосредственно в основной ветке программы.
В приведенной программе к глобальной области видимости относятся заголовки объявлений функций, объявление и присваивание переменной figure , конструкция условного оператора.
К локальной области относятся тела функций. Если, находясь в глобальной области видимости, мы попытаемся обратиться к локальной переменной, то возникнет ошибка:
… elif figure == '2': triangle() print(a)
1-прямоугольник, 2-треугольник: 2 Основание: 4 Высота: 5 Площадь: 10.00 Traceback (most recent call last): File "test.py", line 17, in print(a) NameError: name 'a' is not defined
Однако мы можем обращаться из функций к глобальным переменным:
def rectangle(): a = float(input("Ширина %s: " % figure)) b = float(input("Высота %s: " % figure)) print("Площадь: %.2f" % (a * b)) def triangle(): a = float(input("Основание %s: " % figure)) h = float(input("Высота %s: " % figure)) print("Площадь: %.2f" % (0.5 * a * h)) figure = input("1-прямоугольник, 2-треугольник: ") if figure == '1': rectangle() elif figure == '2': triangle()
1-прямоугольник, 2-треугольник: 1 Ширина 1: 6.35 Высота 1: 2.75 Площадь: 17.46
В данном случае из тел функций происходит обращение к имени figure , которое, из-за того, что было объявлено в глобальной области видимости, видимо во всей программе.
Наши функции не совсем идеальны. Они должны вычислять площади фигур, но выводить результат на экран им не следовало бы. Вполне вероятна ситуация, когда результат нужен для внутренних нужд программы, для каких-то дальнейших вычислений, а выводить ли его на экран – вопрос второстепенный.
Если функции не будут выводить, а только вычислять результат, то его надо где-то сохранить для дальнейшего использования. Для этого подошли бы глобальные переменные. В них можно записать результат. Напишем программу вот так:
def rectangle(): a = float(input("Ширина: ")) b = float(input("Высота: ")) result = a * b def triangle(): a = float(input("Основание: ")) h = float(input("Высота: ")) result = 0.5 * a * h result = 0 figure = input("1-прямоугольник, 2-треугольник: ") if figure == '1': rectangle() elif figure == '2': triangle() print("Площадь: %.2f" % result)
Итак, мы ввели в программу глобальную переменную result и инициировали ее нулем. В функциях ей присваивается результат вычислений. В конце программы ее значение выводится на экран. Мы ожидаем, что программа будет прекрасно работать. Однако…
1-прямоугольник, 2-треугольник: 2 Основание: 6 Высота: 4.5 Площадь: 0.00
… что-то пошло не так.
Дело в том, что в Python присвоение значения переменной совмещено с ее объявлением. (Во многих других языках это не так.) Поэтому, когда имя result впервые упоминается в локальной области видимости, и при этом происходит присваивание ей значения, то создается локальная переменная result . Это другая переменная, никак не связанная с глобальной result .
Когда функция завершает свою работу, то значение локальной result теряется, а глобальная не была изменена.
Когда мы вызывали внутри функции переменную figure , то ничего ей не присваивали. Наоборот, мы запрашивали ее значение. Интерпретатор Питона искал ее значение сначала в локальной области видимости и не находил. После этого шел в глобальную и находил.
В случае с result он ничего не ищет. Он выполняет вычисления справа от знака присваивания, создает локальную переменную result , связывает ее с полученным значением.
На самом деле можно принудительно обратиться к глобальной переменной. Для этого существует команда global :
def rectangle(): a = float(input("Ширина: ")) b = float(input("Высота: ")) global result result = a * b def triangle(): a = float(input("Основание: ")) h = float(input("Высота: ")) global result result = 0.5 * a * h result = 0 figure = input("1-прямоугольник, 2-треугольник: ") if figure == '1': rectangle() elif figure == '2': triangle() print("Площадь: %.2f" % result)
В таком варианте программа будет работать правильно.
Однако менять значения глобальных переменных в теле функции – плохая практика. В больших программах трудно отследить, где, какая функция и почему изменила их значение. Программист смотрит на исходное значение глобальной переменной и может подумать, что оно остается таким же. Сложно заметить, что какая-то функция поменяла его. Подобное ведет к логическим ошибкам.
Чтобы избавиться от необходимости использовать глобальные переменные, для функций существует возможность возврата результата своей работы в основную ветку программы. И уже это полученное из функции значение можно присвоить глобальной переменной в глобальной области видимости. Это делает программу более понятной.
Как функция принимает и возвращает данные, будет рассмотрено в следующих уроках.
Практическая работа
В языке Python можно внутри одной функции определять другую. Напишите программу по следующему описанию.
В основной ветке программы вызывается функция cylinder() , которая вычисляет площадь цилиндра. В теле cylinder определена функция circle , вычисляющая площадь круга по формуле πr 2 . В теле cylinder у пользователя спрашивается, хочет ли он получить только площадь боковой поверхности цилиндра, которая вычисляется по формуле 2πrh, или полную площадь цилиндра. В последнем случае к площади боковой поверхности цилиндра должен добавляться удвоенный результат вычислений функции circle() .
Как вы думаете, можно ли из основной ветки программы вызвать функцию, вложенную в другую функцию? Почему?
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
Вопросы по С/С++ (СИ)
использование static заставляет компилятор сделать загрузку 2 байт в структуру при входе в функцию и сохранение этих 2 байт при выходе, только и всего, никакой другой оптимизации он не делает. не должен делать, во всяком случае.
главное: я не понимаю, что я делаю не так! не первый год это делаю, но в данном случае результат не соответствует ожиданиям! как так-то?!
- technik-1017
- Сообщений: 42
- Зарегистрирован: Вс сен 03, 2017 19:43:57
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 09:59:45
Ассемблерный код все таки наверно придётся смотреть, что бы понять что происходит.
На самом деле у меня было несколько вопросов:
1) переменная entry определена как static, но где тогда происходит первая инициализация. Впервые встречается в условии if и уже сама себя увеличивает (увеличивает мусор?)
2) переменная pos, аналогично пункту 1.
3) переменная regs вроде должна быть (задумано) как static ну и также не инициализирована.
4) переменная two_ms вроде как глобальная, тогда зачем было часть переменных делать глобальными, а часть как static.
Желание избавиться от глобальных переменных? Но по факту они остаются глобальными.
Может пойти классическим путём: в прерывании использовать глобальные переменные с volatile?
По поводу оптимизации static:
в обычных функциях компилятор может понять, что значит переменная static и правильно выполнить оптимизацию. А вот с прерыванием такой фокус может не пройти, т.к. в коде программы прерывание нигде не вызывается как обычная функция и использование static в прерывании для компилятора может выглядеть странно.
То что иногда работает, уже говорили: скорее всего используется память которая ранее была освобождена, и содержала корректные данные от предыдущих действий программы.
- jcxz
- Сообщений: 1077
- Зарегистрирован: Вт авг 15, 2017 10:51:13
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 10:53:55
а вы посмотрите внимательно:
regs.word &= 0xf800;
regs.word |= digs[scr->symbol[entry >= scr->bright]];
младшие 11 бит в каждом прерывании меняются, а старшие 5 — только каждое 62 прерывание.
Я это видел, об этом и писал.
А что значит «со static не работает»? В чём это выражается «не работает»?
Неработать может от того, что кроме этого у вас там есть ещё баги. И их комбинация даёт причудливый результат — когда-то что-то работает, когда-то — нет. Одни баги могут компенсировать/нивелировать действие других.
Например — когда делаете static, то в другом месте другой код, у вас эту область памяти портит. Потому и не работает. Как вариант.
И вообще — как можно о чём-то судить если половину кода не привели и листинга не привели? Только гадать.
Например — что такое static pos_t *scr = screen; и зачем ему (static-переменной scr) на каждом входе в функцию присваивается (переменная/константа/etc.(?)) screen? Какой тут смысл делать статик если по использованию тут нужна обычная автоматическая переменная?
Добавлено after 6 minutes 19 seconds:
1) переменная entry определена как static, но где тогда происходит первая инициализация. Впервые встречается в условии if и уже сама себя увеличивает (увеличивает мусор?)
Не имеющие явной инициализации глобальные/статические переменные, инициализируются 0. Это поведение по умолчанию для си/си++ (может быть измененено соответствующими ключевыми словами компилятора).
Но для самокомментируемости кода, полезно делать явную инициализацию 0-м, чтобы показать для каких переменных это критично. Но не обязательно.
2) переменная pos, аналогично пункту 1.
3) переменная regs вроде должна быть (задумано) как static ну и также не инициализирована.
Хотя бы для начала изучите си.
Может пойти классическим путём: в прерывании использовать глобальные переменные с volatile?
Добавлено after 14 minutes 32 seconds:
вам известны более красивые способы отправки двух байт с последующей дрыгоножной выдачей строба на классическом AVR? посоветуйте, я всегда готов учиться хорошему. а грубить я умею и сам.
Сразу, навскидку, что бросается в глаза — ожидания делать не после записей, а перед. А строб перенести в начало ISR. Это сразу уменьшает ожидание внутри ISR на эти самые 16 тактов.
PS: Чисто теоретически я бы выбрал другой МК: с DMA (для SPI) или с FIFO (в SPI). И эти проблемы бы сами собой отпали. Например STM8Lxx.
- ARV
- Сообщений: 17994
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 11:57:12
jcxz писал(а): А что значит «со static не работает»? В чём это выражается «не работает»?
как минимум в том, что в обычном случае добавление static к любой локальной переменной никаких побочных эффектов, кроме увеличения статически выделенной памяти, давать не должно, т.е. что со static, что без, поведение программы должно быть неизменным. в моём случае это не так.
jcxz писал(а): Например — когда делаете static, то в другом месте другой код, у вас эту область памяти портит. Потому и не работает. Как вариант.
невероятный вариант: локальная переменная потому и локальная, что более нигде не используется, хоть со static, хоть без. а всякие «опасные» действия (с указателями) у меня отсутствуют в коде.
jcxz писал(а): Например — что такое static pos_t *scr = screen; и зачем ему (static-переменной scr) на каждом входе в функцию присваивается (переменная/константа/etc.(?)) screen? Какой тут смысл делать статик если по использованию тут нужна обычная автоматическая переменная?
для локальной static-переенной это присваивание делается один раз, по идее вы не должны были спрашивать это, это ведь азы Си. для первого входа в обработчик надо, чтобы указатель указывал на начало массива, а в ходе обработки (см. код) этот указатель сдвигается.
jcxz писал(а): ожидания делать не после записей, а перед. А строб перенести в начало ISR. Это сразу уменьшает ожидание внутри ISR на эти самые 16 тактов.
ну, это, наверное, сделать можно, хотя фактически получится, что состояние индикаторов будет отставать от того, что делает обработчик но вряд ли это критично. 16 тактов, я имею ввиду.
jcxz писал(а): я бы выбрал другой МК
выбирайте, я не запрещаю.
technik-1017 писал(а): переменная regs вроде должна быть (задумано) как static ну и также не инициализирована
так о том и речь: когда эта переменная БЕЗ static, т.е. содержит мусор на входе в функцию, все работает, а когда я делаю её static, т.е. она на первом входе уже инициализирована нулями — работать перестаёт.
- mont-oriol
- Сообщений: 437
- Зарегистрирован: Пн май 27, 2019 07:18:28
- Откуда: ВВХ-ск
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 13:12:39
когда эта переменная БЕЗ static, т.е. содержит мусор на входе в функцию, все работает, а когда я делаю её static, т.е. она на первом входе уже инициализирована нулями — работать перестаёт.
==
Когда переменная находится в одной области памяти, все работает, а когда переносится в другую область памяти — работать перестаёт?
Возможно, что-то портит ту область, где static переменные. Может стек туда наезжает. Для проверки можно сделать переменную глобальной, и объявить её выше / ниже по отношению к другим переменным, так, чтобы можно было менять её адрес расположения в памяти. Если окажется, что при таком перемещении переменной всё заработало — вывод очевиден.
- WiseLord
- Сообщений: 4848
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 13:31:18
Кстати, вот это Код: static pos_t *scr = screen; действительно опаснее, чем выглядит. Хотя, если screen — тоже static и представляет собой массив pos_t, то всё вроде выглядит ОК — один раз оно получит своё значение, а дальше уже будет итерироваться/сбрасываться.
Хотя я бы, наверное, вообще убрал эту переменную, а просто обращался бы к screen[pos].symbol[n], так как scr и pos фактически друг друга дублируют
Если идти последовательно:
При старте программы все static переменные получают свои значения (не важно, локальные они или нет):
entry = 0;
pos = 0;
scr = screen;
Далее, при первом входе в прерывание:
regs = . ; // не определено значение
Условие «считаем входы» не выполняется, поэтому regs так и остаётся неопределённым. Поэтому далее в regs.word состояние 5 старших битов так и остаётся непонятным в течение как минимум IND_RPT раз. И только 1 раз из IND_RPT у нас значение старших 5 байтов regs определено. Остальные — просто «везёт» из-за попадания в ту же ячейку памяти на стеке.
А вот почему код, если regs сделать static, ломается — действительно странно. Потому как после IND_RPT вхождений в прерывание индикация должна бы наладиться
Добавлено after 1 minute 34 seconds:
Может, и правда ОЗУ уже не хватает и стек наезжает на область статических переменных.
- technik-1017
- Сообщений: 42
- Зарегистрирован: Вс сен 03, 2017 19:43:57
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 13:37:33
Скорее всего static в Си не может использоваться со структурами (так как мы этого хотим в данном примере) и конечно их не инициализирует (инициализировать структуру нужно принудительно).
static используется только для ограничения видимости. Попробуйте сделать структуру глобальной переменной.
- jcxz
- Сообщений: 1077
- Зарегистрирован: Вт авг 15, 2017 10:51:13
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 13:45:21
jcxz писал(а): А что значит «со static не работает»? В чём это выражается «не работает»?
как минимум в том
Вы не поняли вопрос. Перечитайте ещё раз.
ARV писал(а):
jcxz писал(а): Например — когда делаете static, то в другом месте другой код, у вас эту область памяти портит. Потому и не работает. Как вариант.
невероятный вариант: локальная переменная потому и локальная, что более нигде не используется, хоть со static, хоть без.
И что что «не используется»? Она в памяти присутствует? Рядом с ней другие переменные (static или глобальные) присутствуют? А раз присутствуют, значит любая неправильная операция с памятью может её порушить.
ARV писал(а): а всякие «опасные» действия (с указателями) у меня отсутствуют в коде.
Ну да, а ещё вы пишете абсолютно безглючный код, который никогда не глючит. Зачем тогда вопрос задали раз у вас ничего не глючит?
ARV писал(а): для локальной static-переенной это присваивание делается один раз, по идее вы не должны были спрашивать это, это ведь азы Си.
А вам по идее с этого места надо взять учебник по си и начать изучать азы. Ибо смотрим в листинг (IAR):
Код: inline void CpuUseTimeTick()
_Z14CpuUseTimeTickv: (+1)
.
//static u16 t = cpuUseCalc;
0x4821 LDR.N R0. CpuUseTimeTick_0+0x8
0x78C0 LDRB R0,[R0, #+3]
0x8020 STRH R0,[R4, #+0]
.
Как видим — нормально так static переменной t присваивается значение переменной cpuUseCalc на каждом входе в функцию CpuUseTimeTick().
Или думаете это IAR не знает азов си? Или всё-таки вы их не знаете?
PS: Складывается ощущение, что это не у вас эти баги, а у меня. К советам вы не прислушиваетесь, ещё и спорите. Зачем тогда вообще вопрос задали?
Баги эти вроде не у меня. И мне абсолютно на них насрать. Не нужно вам найти решение — воля ваша. Зачем тогда было спрашивать?
Добавлено after 1 minute 2 seconds:
Возможно, что-то портит ту область, где static переменные.
Я уже это советовал автору. Но не принимает никаких советов.
Добавлено after 2 minutes 35 seconds:
Кстати, вот это Код: static pos_t *scr = screen; действительно опаснее, чем выглядит. Хотя, если screen — тоже static и представляет собой массив pos_t
Я ещё в самом начале советовал автору привести определения всех объектов и типов, фигурирующих в примере кода. Чтобы не играть в угадайку. Но он проигнорировал. Видимо ищет здесь гадалок.
Добавлено after 2 minutes 10 seconds:
А вот почему код, если regs сделать static, ломается — действительно странно.
Очень просто — наверняка там ещё табун других багов рядом пасётся. которые иногда проявляются, иногда — нет. Как карты лягут.
- technik-1017
- Сообщений: 42
- Зарегистрирован: Вс сен 03, 2017 19:43:57
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 14:18:01
Только что проверил в IAR AVR
— если объявить структуру как static (не инициализированную), то компилятор просто выкидывает кусок кода, где используется структура
— если объявить структуру без static, то код не выбрасывается, но переменная локальная
— если объявить структуру volatile static, то код не выбрасывается, но куда указывает, не успел проверить (пора домой, дома позже могу проверить)
- Reflector
- Сообщений: 1950
- Зарегистрирован: Вс июн 19, 2016 09:32:03
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 15:31:53
Код: inline void CpuUseTimeTick()
_Z14CpuUseTimeTickv: (+1)
.
//static u16 t = cpuUseCalc;
0x4821 LDR.N R0. CpuUseTimeTick_0+0x8
0x78C0 LDRB R0,[R0, #+3]
0x8020 STRH R0,[R4, #+0]
.
Как видим — нормально так static переменной t присваивается значение переменной cpuUseCalc на каждом входе в функцию CpuUseTimeTick().
Это не более чем результат оптимизации, если после использования переменной t присвоить новое значение, то компилятор может добавить флаг говорящий о том нужно ли загружать в переменную значение cpuUseCalc, а может он перезапишет значение самой cpuUseCalc, если она больше нигде не используется, тогда одна загрузка и останется.
- ARV
- Сообщений: 17994
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 16:05:02
WiseLord писал(а): действительно опаснее, чем выглядит
почему? screen — это массив, он не static, но адрес-то его неизменен, и присваивание его указателю, по-моему, совершенно безопасно.
WiseLord писал(а): ОЗУ уже не хватает и стек наезжает на область статических переменных..
у меня atmega328 и в коде статически задействовано 63 байта ОЗУ — там еще немеряно памяти! никаких наездов нет и быть не может.
jcxz писал(а): Перечитайте ещё раз
я не могу сказать точнее, чем сформулировал ранее: добавление static к локальной переменной ломать код не должно по определению. поэтому «не работает» выражается в том, что работа кода ломается. а эффекты от этого могут быть разные — от нарушения индикации (одновременное свечение соседних разрядов) до полной абракадабры индикации (хаотические мерцания, скакания цифр и их яркости).
jcxz писал(а): А раз присутствуют, значит любая неправильная операция с памятью может её порушить.
теоретически — да, но на практике — откуда взяться неправильной операции с памятью?! memcpy и strcpy я не использую, как не использую и аналогичных «самописных» функций, заполняющих/изменяющих области памяти по указателю. других способов разрушить «соседние» переменные (не считая переполнения стека) я не знаю. а стек не переполняется — см. выше
jcxz писал(а): вы пишете абсолютно безглючный код, который никогда не глючит
сам по себе код не глючит, это я где-то что-то сделал не так. только я не могу понять, что именно не так.
поскольку остальная часть кода работает (как минимум — визуально) надежно, грешу только на этот обработчик прерывания.
jcxz писал(а): Или думаете это IAR не знает азов си? Или всё-таки вы их не знаете?
может быть, я и не знаю. но вот предыдущие 10 лет программирования как-то static-ом для локальных переменных пользовался, и ни разу проблем не испытывал, а тут вот оно чо. азы поменялись? а что делает IAR — я не в курсе, мне сейчас больше интересно, что avr-gcc делает. по листингам он делает все правильно, т.е. static-и сохраняет/загружает, auto-переменные не инициализирует никак. и, как ранее было сказано, для не-static варианта на 64-ю итерацию прерывания все устаканивается, а со static — нет. вот в чем вопрос.
jcxz писал(а): Я ещё в самом начале советовал автору привести определения всех объектов и типов, фигурирующих в примере кода. Чтобы не играть в угадайку.
это можно, хотя поможет навряд ли. Код: static const __flash uint16_t digs[CHAR_CNT] = <
CHAR_0, CHAR_1, CHAR_2, CHAR_3, CHAR_4,
CHAR_5, CHAR_6, CHAR_7, CHAR_8, CHAR_9,
CHAR_PU, CHAR_PD, CHAR_PB, CHAR_SP
>;
/// структура знакоместа
typedef struct volatile uint8_t bright; //! < заданная яркость
volatile char_t symbol[2]; //!< коды знака
> pos_t;
// структура для управления индикаторами через регистры 74HC595
typedef union struct uint16_t symbol : 11; // код символа
uint8_t anode : POS_CNT; // бит разряда
>;
uint8_t bytes[2]; // 2 байта для выдачи в регистры
uint16_t word;
> regs_t;
///*
ISR(TIMER1_OVF_vect) static uint8_t entry;
static uint8_t anode = 0x08;
uint16_t word;
static pos_t *scr = screen;
word = digs[scr->symbol[entry >= scr->bright]];
if(entry < 50)
word |= anode
if(++entry >= IND_RPT) entry = 0;
two_ms++;
scr++;
anode if(anode == 0) anode = 0x08;
scr = screen;
>
>
SPDR = word >> 8;
while(bit_is_clear(SPSR, SPIF));
SPDR = word;
while(bit_is_clear(SPSR, SPIF));
// строб для защелкивания данных
PORTB |= LOAD_PIN;
PORTB &= ~LOAD_PIN;
>
теперь все ясно по типам данных?
Добавлено after 3 minutes 32 seconds:
да, я привел уже немного модифицированный код, поскольку постоянно пытаюсь разобраться с ним. он хоть и отличается от предыдущего мной показанного, но проблему сохраняет: сейчас вместо regs используется тупо uint16_t word — и тем не менее эффект прежний: эта переменная, будучи автоматической, обеспечивает работу кода, а будучи static — портит.
- WiseLord
- Сообщений: 4848
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 16:38:20
А можно ещё уточнить по значениям POS_CNT, IND_RPT. А то без этого логика не до конца ясна (особенно проверка entry < 50)
- jcxz
- Сообщений: 1077
- Зарегистрирован: Вт авг 15, 2017 10:51:13
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 16:52:07
откуда взяться неправильной операции с памятью?! memcpy и strcpy я не использую, как не использую и аналогичных «самописных» функций, заполняющих/изменяющих области памяти по указателю. других способов разрушить «соседние» переменные (не считая переполнения стека)
Вы используете указатели . Одного этого достаточно чтобы порушить память.
Добавлено after 6 minutes 58 seconds:
А можно ещё уточнить по значениям POS_CNT, IND_RPT. А то без этого логика не до конца ясна (особенно проверка entry < 50)
Как партизан на допросе. под пытками выдаёт по капле инфу. хотя вроде же ему нужны советы.
- WiseLord
- Сообщений: 4848
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 16:58:50
Ещё момент. word = digs[blablabla] — тут не возникнет переполнения?
Значение CHAR_CNT нам неизвестно (как и CHAR_0 сотоварищи), поэтому есть ли гарантия, что где-то в scr->symbol[0] или scr->symbol[1] не лежит число большее либо равное этому CHAR_CNT?
- ARV
- Сообщений: 17994
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 17:01:26
IND_RPT = 63;
POS_CNT = 5;
смысл вот в чем: entry считает входы. поле bright в структуре pos_t определяет значение, до которого выводится bytes[0], а свыше — bytes[1] этой структуры. таким образом от 0-го входа до bright светится первый символ, а от bright до 63-го входа — второй. сравнение с 50 делал для того, чтобы укоротить свечение второго, принудительно отключив анод индикатора — думал, вдруг оптрон долго запирается, что и дает эффекты одновременного свечения разрядов. по документам 10 мкс время выключения оптрона — прилично, по МК-шным меркам.
в контексте моих проблем на это сравнение можно не обращать внимание
WiseLord писал(а): CHAR_CNT неизвестна, но есть ли гарантия, что где-то в scr->symbol[0] или scr->symbol[1] не лежит число большее либо равно этому?
гарантия есть: всего 10 символов для цифр, 3 варианта для точек и 1 «пустой» символ — итого 14.
- WiseLord
- Сообщений: 4848
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 17:02:56
А сами символы? Что именно такое CHAR_0?
Я почему спрашиваю. Вот идёт код
Код: word = digs[scr->symbol[entry >= scr->bright]];
В зависимости от яркости и entry, это может быть одно из двух:
Код: word = digs[scr->symbol[0]];
word = digs[scr->symbol[1]];
scr->symbol[i] — это какая-то 11-битная переменная, например, 0x0482 = 1154
Вопрос, насколько правомерно тогда digs[1154] ?
Хотя.. я, видимо, не туда глянул, и там всё же не 11-битная symbol из regs_t, а char из pos_t. Тогда это будет скорее не код знака, а его индекс в массиве, меньший CHAR_CNT
- ARV
- Сообщений: 17994
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 17:12:18
WiseLord писал(а): scr->symbol[i] — это какая-то 11-битная переменная, например, 0x0482 = .1154
Вопрос, насколько правомерно тогда digs[1154] ?
переменная scr->symbol[i] 8-битная, см. структуру pos_t. содержит эта переменная код символов от 0 до 13. коды эти получаются самописной функцией, аналогичной itoa по смыслу. а вот digs[] — это уже массив 11-битных переменных
здесь не может быть проблем
- WiseLord
- Сообщений: 4848
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Сайт
Re: Вопросы по С/С++ (СИ)
Вт июн 15, 2021 17:18:26
Да, я уже «проэмулировал» на компьютере:
Код: #include
#define CHAR_CNT 14
#define POS_CNT 5
#define IND_RPT 63
#define CHAR_0 0x000
#define CHAR_1 0x111
#define CHAR_2 0x222
#define CHAR_3 0x333
#define CHAR_4 0x444
#define CHAR_5 0x555
#define CHAR_6 0x666
#define CHAR_7 0x777
#define CHAR_8 0x888
#define CHAR_9 0x999
#define CHAR_PU 0xaaa
#define CHAR_PD 0xbbb
#define CHAR_PB 0xccc
#define CHAR_SP 0xddd
static const uint16_t digs[CHAR_CNT] = CHAR_0, CHAR_1, CHAR_2, CHAR_3, CHAR_4,
CHAR_5, CHAR_6, CHAR_7, CHAR_8, CHAR_9,
CHAR_PU, CHAR_PD, CHAR_PB, CHAR_SP
>;
/// структура знакоместа
typedef struct volatile uint8_t bright; //! < заданная яркость
volatile char symbol[2]; //!< коды знака
> pos_t;
// структура для управления индикаторами через регистры 74HC595
typedef union struct uint16_t symbol : 11; // код символа
uint8_t anode : POS_CNT; // бит разряда
>;
uint8_t bytes[2]; // 2 байта для выдачи в регистры
uint16_t word;
> regs_t;
void ISR() static uint8_t entry;
static uint8_t anode = 0x08;
uint16_t word;
static pos_t *scr = screen;
word = digs[scr->symbol[entry >= scr->bright]];
if(entry < 50)
word |= anode
if(++entry >= IND_RPT) entry = 0;
scr++;
anode if(anode == 0) anode = 0x08;
scr = screen;
>
>
printf(«entry=%2d: word=%04x\n», entry, word);
>
int main()
screen[0].symbol[0] = 1;
screen[0].symbol[1] = 2;
screen[0].bright = 4;
screen[1].symbol[0] = 3;
screen[1].symbol[1] = 4;
screen[1].bright = 3;
screen[2].symbol[0] = 5;
screen[2].symbol[1] = 6;
screen[2].bright = 2;
screen[3].symbol[0] = 7;
screen[3].symbol[1] = 8;
screen[3].bright = 1;
screen[4].symbol[0] = 9;
screen[4].symbol[1] = 10;
screen[4].bright = 2;
Код: entry= 1: word=0911
entry= 2: word=0911
entry= 3: word=0911
entry= 4: word=0911
entry= 5: word=0a22
entry= 6: word=0a22
entry= 7: word=0a22
entry= 8: word=0a22
entry= 9: word=0a22
entry=10: word=0a22
entry=11: word=0a22
entry=12: word=0a22
entry=13: word=0a22
entry=14: word=0a22
entry=15: word=0a22
entry=16: word=0a22
entry=17: word=0a22
entry=18: word=0a22
entry=19: word=0a22
entry=20: word=0a22
entry=21: word=0a22
entry=22: word=0a22
entry=23: word=0a22
entry=24: word=0a22
entry=25: word=0a22
entry=26: word=0a22
entry=27: word=0a22
entry=28: word=0a22
entry=29: word=0a22
entry=30: word=0a22
entry=31: word=0a22
entry=32: word=0a22
entry=33: word=0a22
entry=34: word=0a22
entry=35: word=0a22
entry=36: word=0a22
entry=37: word=0a22
entry=38: word=0a22
entry=39: word=0a22
entry=40: word=0a22
entry=41: word=0a22
entry=42: word=0a22
entry=43: word=0a22
entry=44: word=0a22
entry=45: word=0a22
entry=46: word=0a22
entry=47: word=0a22
entry=48: word=0a22
entry=49: word=0a22
entry=50: word=0a22
entry=51: word=0222
entry=52: word=0222
entry=53: word=0222
entry=54: word=0222
entry=55: word=0222
entry=56: word=0222
entry=57: word=0222
entry=58: word=0222
entry=59: word=0222
entry=60: word=0222
entry=61: word=0222
entry=62: word=0222
entry= 0: word=0222
entry= 1: word=1333
entry= 2: word=1333
entry= 3: word=1333
entry= 4: word=1444
entry= 5: word=1444
entry= 6: word=1444
entry= 7: word=1444
entry= 8: word=1444
entry= 9: word=1444
entry=10: word=1444
entry=11: word=1444
entry=12: word=1444
entry=13: word=1444
entry=14: word=1444
entry=15: word=1444
entry=16: word=1444
entry=17: word=1444
entry=18: word=1444
entry=19: word=1444
entry=20: word=1444
entry=21: word=1444
entry=22: word=1444
entry=23: word=1444
entry=24: word=1444
entry=25: word=1444
entry=26: word=1444
entry=27: word=1444
entry=28: word=1444
entry=29: word=1444
entry=30: word=1444
entry=31: word=1444
entry=32: word=1444
entry=33: word=1444
entry=34: word=1444
entry=35: word=1444
entry=36: word=1444
entry=37: word=1444
entry=38: word=1444
entry=39: word=1444
entry=40: word=1444
entry=41: word=1444
entry=42: word=1444
entry=43: word=1444
entry=44: word=1444
entry=45: word=1444
entry=46: word=1444
entry=47: word=1444
entry=48: word=1444
entry=49: word=1444
entry=50: word=1444
entry=51: word=0444
entry=52: word=0444
entry=53: word=0444
entry=54: word=0444
entry=55: word=0444
entry=56: word=0444
entry=57: word=0444
entry=58: word=0444
entry=59: word=0444
entry=60: word=0444
entry=61: word=0444
entry=62: word=0444
entry= 0: word=0444
entry= 1: word=2555
entry= 2: word=2555
entry= 3: word=2666
entry= 4: word=2666
entry= 5: word=2666
entry= 6: word=2666
entry= 7: word=2666
entry= 8: word=2666
entry= 9: word=2666
entry=10: word=2666
entry=11: word=2666
entry=12: word=2666
entry=13: word=2666
entry=14: word=2666
entry=15: word=2666
entry=16: word=2666
entry=17: word=2666
entry=18: word=2666
entry=19: word=2666
entry=20: word=2666
entry=21: word=2666
entry=22: word=2666
entry=23: word=2666
entry=24: word=2666
entry=25: word=2666
entry=26: word=2666
entry=27: word=2666
entry=28: word=2666
entry=29: word=2666
entry=30: word=2666
entry=31: word=2666
entry=32: word=2666
entry=33: word=2666
entry=34: word=2666
entry=35: word=2666
entry=36: word=2666
entry=37: word=2666
entry=38: word=2666
entry=39: word=2666
entry=40: word=2666
entry=41: word=2666
entry=42: word=2666
entry=43: word=2666
entry=44: word=2666
entry=45: word=2666
entry=46: word=2666
entry=47: word=2666
entry=48: word=2666
entry=49: word=2666
entry=50: word=2666
entry=51: word=0666
entry=52: word=0666
entry=53: word=0666
entry=54: word=0666
entry=55: word=0666
entry=56: word=0666
entry=57: word=0666
entry=58: word=0666
entry=59: word=0666
entry=60: word=0666
entry=61: word=0666
entry=62: word=0666
entry= 0: word=0666
entry= 1: word=4777
entry= 2: word=4888
entry= 3: word=4888
entry= 4: word=4888
entry= 5: word=4888
entry= 6: word=4888
entry= 7: word=4888
entry= 8: word=4888
entry= 9: word=4888
entry=10: word=4888
entry=11: word=4888
entry=12: word=4888
entry=13: word=4888
entry=14: word=4888
entry=15: word=4888
entry=16: word=4888
entry=17: word=4888
entry=18: word=4888
entry=19: word=4888
entry=20: word=4888
entry=21: word=4888
entry=22: word=4888
entry=23: word=4888
entry=24: word=4888
entry=25: word=4888
entry=26: word=4888
entry=27: word=4888
entry=28: word=4888
entry=29: word=4888
entry=30: word=4888
entry=31: word=4888
entry=32: word=4888
entry=33: word=4888
entry=34: word=4888
entry=35: word=4888
entry=36: word=4888
entry=37: word=4888
entry=38: word=4888
entry=39: word=4888
entry=40: word=4888
entry=41: word=4888
entry=42: word=4888
entry=43: word=4888
entry=44: word=4888
entry=45: word=4888
entry=46: word=4888
entry=47: word=4888
entry=48: word=4888
entry=49: word=4888
entry=50: word=4888
entry=51: word=0888
entry=52: word=0888
entry=53: word=0888
entry=54: word=0888
entry=55: word=0888
entry=56: word=0888
entry=57: word=0888
entry=58: word=0888
entry=59: word=0888
entry=60: word=0888
entry=61: word=0888
entry=62: word=0888
entry= 0: word=0888
entry= 1: word=8999
entry= 2: word=8999
entry= 3: word=8aaa
entry= 4: word=8aaa
entry= 5: word=8aaa
entry= 6: word=8aaa
entry= 7: word=8aaa
entry= 8: word=8aaa
entry= 9: word=8aaa
entry=10: word=8aaa
entry=11: word=8aaa
entry=12: word=8aaa
entry=13: word=8aaa
entry=14: word=8aaa
entry=15: word=8aaa
entry=16: word=8aaa
entry=17: word=8aaa
entry=18: word=8aaa
entry=19: word=8aaa
entry=20: word=8aaa
entry=21: word=8aaa
entry=22: word=8aaa
entry=23: word=8aaa
entry=24: word=8aaa
entry=25: word=8aaa
entry=26: word=8aaa
entry=27: word=8aaa
entry=28: word=8aaa
entry=29: word=8aaa
entry=30: word=8aaa
entry=31: word=8aaa
entry=32: word=8aaa
entry=33: word=8aaa
entry=34: word=8aaa
entry=35: word=8aaa
entry=36: word=8aaa
entry=37: word=8aaa
entry=38: word=8aaa
entry=39: word=8aaa
entry=40: word=8aaa
entry=41: word=8aaa
entry=42: word=8aaa
entry=43: word=8aaa
entry=44: word=8aaa
entry=45: word=8aaa
entry=46: word=8aaa
entry=47: word=8aaa
entry=48: word=8aaa
entry=49: word=8aaa
entry=50: word=8aaa
entry=51: word=0aaa
entry=52: word=0aaa
entry=53: word=0aaa
entry=54: word=0aaa
entry=55: word=0aaa
entry=56: word=0aaa
entry=57: word=0aaa
entry=58: word=0aaa
entry=59: word=0aaa
entry=60: word=0aaa
entry=61: word=0aaa
entry=62: word=0aaa
entry= 0: word=0aaa
entry= 1: word=0911
entry= 2: word=0911
entry= 3: word=0911
entry= 4: word=0911
entry= 5: word=0a22
entry= 6: word=0a22
entry= 7: word=0a22
entry= 8: word=0a22
entry= 9: word=0a22
entry=10: word=0a22
entry=11: word=0a22
—>
Вроде бы всё как задумывалось, и от static не зависит.
- jcxz
- Сообщений: 1077
- Зарегистрирован: Вт авг 15, 2017 10:51:13