Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Принудительное размещение локальной переменной в стеке
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
Petrooo
Добрый день, уважаемые коллеги!
Компилятор размещает локальные переменные, определенные в теле функции либо в регистрах, либо в стеке.
Код
void Func(char Var1) {
char Var2;
...
Var2 = Var1;
...
}

Если переменная 1 или 2-х байтная, то скорее всего компилятор ее разместит в регистрах.
А мне нужно, чтобы он принудительно разместил ее (Var2) в сегменте стека.
А еще лучше, если сразу Var1 будет размещаться в стеке.
Как мне его это заставить сделать?
vmp
Цитата(Petrooo @ Feb 12 2007, 17:31) *
А мне нужно, чтобы он принудительно разместил ее (Var2) в сегменте стека.


Вызвать подпрограмму, которой передать в качестве аргумента адрес Var2.


void dummy(int *p)
{
}

void func(void)
{
int Var2;
dummy(&var2);
}
Dog Pawlowa
Цитата(vmp @ Feb 12 2007, 19:13) *
Вызвать подпрограмму, которой передать в качестве аргумента адрес Var2.

Компилятор может точно так же поместить в регистры указатель.
Поэтому встает вопрос о целях автора. Какая разница, где переменная, указатель и прочее?
По большому счету задай оптимизацию - по коду или быстродействию и отдайся компилятору, закрыв глаза. wink.gif
vmp
Цитата(Dog Pawlowa @ Feb 12 2007, 18:55) *
Цитата(vmp @ Feb 12 2007, 19:13) *

Вызвать подпрограмму, которой передать в качестве аргумента адрес Var2.

Компилятор может точно так же поместить в регистры указатель.

В вызываемой подпрограмме - да. А в вызывающей переменная будет создана на стеке, ибо регистры (по крайней мере в данной архитектуре) адреса не имеют.
rezident
Цитата(vmp @ Feb 12 2007, 21:21) *
Цитата(Dog Pawlowa @ Feb 12 2007, 18:55) *

Цитата(vmp @ Feb 12 2007, 19:13) *

Вызвать подпрограмму, которой передать в качестве аргумента адрес Var2.

Компилятор может точно так же поместить в регистры указатель.

В вызываемой подпрограмме - да. А в вызывающей переменная будет создана на стеке, ибо регистры (по крайней мере в данной архитектуре) адреса не имеют.

Это зависит от компилятора. В IAR, например, передача параметров функции производится через регистры R15-R12. Если же размер параметров функции превышает совокупный размер этих регистров то тогда да, параметры передаются через стек.
Сергей Борщ
Цитата(rezident @ Feb 12 2007, 19:50) *
Если же размер параметров функции превышает совокупный размер этих регистров то тогда да, параметры передаются через стек.
Для того, чтобы передать адрес переменной, эта переменная должна иметь адрес, т.е. находиться в памяти а не в регистрах. Что и требовалось.
rezident
Цитата(Сергей Борщ @ Feb 12 2007, 23:06) *
Цитата(rezident @ Feb 12 2007, 19:50) *

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

Извиняюсь, невнимательно прочитал сообщения топика.
Сергей Борщ
Цитата(rezident @ Feb 12 2007, 21:31) *
Извиняюсь, невнимательно прочитал сообщения топика.
Похоже я тоже невнимательно читал. Если передавать Var1 прямо в стеке, можно попробовать что-то вроде
Код
typedef struct
{
   char Value;
} char_struct_t;

void Func(char_struct_t Var1)
По идее структура должна передаваться через стек, но никто не гарантирует, что оптимизатор не окажется слишком умным и не решит, что такая структура влезет и в регистр.
Dog Pawlowa
Цитата(Сергей Борщ @ Feb 13 2007, 00:07) *
но никто не гарантирует, что оптимизатор не окажется слишком умным и не решит, что такая структура влезет и в регистр.

Ребят, ну давайте не пытаться быть умнее компилятора! :-)
Я вот прикинул.... Я пишу программы для микропроцессоров и микроконтроллеров 22 года, из них 16 последних на ЯВУ, и ни разу не задумывался, как передаются параметры в функцию.
Petrooo
ссори за долгое отсутствие
Цитата(Dog Pawlowa @ Feb 13 2007, 10:37) *
Ребят, ну давайте не пытаться быть умнее компилятора! :-)
Я вот прикинул.... Я пишу программы для микропроцессоров и микроконтроллеров 22 года, из них 16 последних на ЯВУ, и ни разу не задумывался, как передаются параметры в функцию.

Пишу для микропроцессоров менее 22 лет, но вот пришлось задуматься где передаются параметры smile.gif
Есть девайс (ККМ), в котором пользователь иногда запускает "критический" процесс с "критическими" секциями исполнения программы. Например печать журнала чеков. Если при печати вырубается питание, то по включении ККМ должна продолжить печать с того чека, на котором прервалась печать. Причем все накопления по предыдущим чекам не должны пропасть.
Что я делаю:
1. при выключении питания по прерыванию сохраняю адрес критической секции (печать одного чека)
2. ее параметры - номер чека и прочее
3 и стек в котором лежат локальные переменные

По включению девайс:
1. проходит все начальные тесты и прочее
2. смотрит была ли "свертка"
3. если была, восстанавливаю адрес верхушки стека
Код
asm ("MOV.W  &SVERTKA+2, SP");

и его содержимое
4. перехожу по адресу
Код
asm ("BR     &SVERTKA+4");


Теперь, полагаю, уважаемой публике стало понятно, почему собственно встал вопрос топика.
Локальные переменные, которые в стеке свои значения "сохранили" от старого сеанса,
а которые в регистрах - похерились!
Можно, конечно, при свертке еще и регисты сохранять, но думал, что можно забороть умный копмилятор еще более умной директивой или ключевым словом, которые я не нарыл smile.gif
Пока решил проблему так:
чтобы меньше переделывать код тупо "умыл" компилятор, объявив Var2 8-ым байтным long long'ом (в регистры запухнуть это копмилятору оказалось слабо)!

Кстати, если мне не изменяет память, я уже как то поднимал эту тему на форуме, было бы интересно узнать, кто как сворачивается-разворачивается по выкл/вкл в аналогичных ситуациях.
rezident
Цитата(Petrooo @ Feb 13 2007, 17:15) *
Кстати, если мне не изменяет память, я уже как то поднимал эту тему на форуме, было бы интересно узнать, кто как сворачивается-разворачивается по выкл/вкл в аналогичных ситуациях.

ИМХО проще иметь глобальную структуру глобальных переменных. Тогда критические данные можно разместить последовательно (рядом) в такой структуре. Сохранять их в таком случае проще - всегда известно где они лежат и каков размер критической секции данных.
"Рубанули питание" для случая применения MSP430 звучит несколько странно. Если есть детектор "вырубания", то конденсатора на две-три сотни мкФ или ионистора (или литиевой батарейки на худой конец) вполне хватит чтобы завершить сохранение критически важных данных.
АДИКМ
Цитата(Petrooo @ Feb 13 2007, 16:15) *
ссори за долгое отсутствие
Цитата(Dog Pawlowa @ Feb 13 2007, 10:37) *

Ребят, ну давайте не пытаться быть умнее компилятора! :-)
Я вот прикинул.... Я пишу программы для микропроцессоров и микроконтроллеров 22 года, из них 16 последних на ЯВУ, и ни разу не задумывался, как передаются параметры в функцию.

Пишу для микропроцессоров менее 22 лет, но вот пришлось задуматься где передаются параметры smile.gif
Есть девайс (ККМ), в котором пользователь иногда запускает "критический" процесс с "критическими" секциями исполнения программы. Например печать журнала чеков. Если при печати вырубается питание, то по включении ККМ должна продолжить печать с того чека, на котором прервалась печать. Причем все накопления по предыдущим чекам не должны пропасть.
Что я делаю:
1. при выключении питания по прерыванию сохраняю адрес критической секции (печать одного чека)
2. ее параметры - номер чека и прочее
3 и стек в котором лежат локальные переменные

По включению девайс:
1. проходит все начальные тесты и прочее
2. смотрит была ли "свертка"
3. если была, восстанавливаю адрес верхушки стека
Код
asm ("MOV.W  &SVERTKA+2, SP");

и его содержимое
4. перехожу по адресу
Код
asm ("BR     &SVERTKA+4");


Теперь, полагаю, уважаемой публике стало понятно, почему собственно встал вопрос топика.
Локальные переменные, которые в стеке свои значения "сохранили" от старого сеанса,
а которые в регистрах - похерились!
Можно, конечно, при свертке еще и регисты сохранять, но думал, что можно забороть умный копмилятор еще более умной директивой или ключевым словом, которые я не нарыл smile.gif
Пока решил проблему так:
чтобы меньше переделывать код тупо "умыл" компилятор, объявив Var2 8-ым байтным long long'ом (в регистры запухнуть это копмилятору оказалось слабо)!

Кстати, если мне не изменяет память, я уже как то поднимал эту тему на форуме, было бы интересно узнать, кто как сворачивается-разворачивается по выкл/вкл в аналогичных ситуациях.



Скажите, а как Вы успеваете сохранится? Ведь у вас термопринтер потребляет немало...
Вы уверены, что Z или X отчет надо продолжать печатать с того же места, а не заново?

А для того чтобы данные передавались как вам надо, может проще эти процедуры на ассемблере написать?
Dog Pawlowa
Цитата(Petrooo @ Feb 13 2007, 16:15) *
Кстати, если мне не изменяет память, я уже как то поднимал эту тему на форуме, было бы интересно узнать, кто как сворачивается-разворачивается по выкл/вкл в аналогичных ситуациях.


Ну, теперь понятно smile.gif

1. Использую измерение напряжения до стабилизатора, чтобы вовремя отключить все энергопотребляющие узлы, чтобы контроллер насладился сохранением статистики в ЕЕПРОМ.
2. Чтобы статистика не попортилась, делаю это только только в критических местах.
3. Реализую алгоритм прибора в виде массива функций, а текущим индексом массива является глобальная переменная "статус".
4. Не использую стек для таких функций, но, чтобы памяти хватило, использую одни и те же глобальные переменные в каждой функции, переопределяя их каждый раз в целях соответствия имени физическому смыслу (комментарии не пишу, компенсируя это именами).

Собственно, все... После сброса контроллер инициализируется и сразу выходит на ту функцию, где он был.

Были мысли про стек, но больше риск влететь куда-то не туда, и возникает зависимость от платформы, а я это не люблю - контроллеры приходят и уходят, а люди остаются smile.gif

Да, еще... (прочитал, что написал ув. Rezident) - пп 3 и 4 нужны , если нужно быстро перезапуститься (например, помехи жуткие и проч.) Если обычный процесс выключения, пусть нештатного - можно ведь сохраниться в EEPROM без проблем - т.е. пп. 1 и 2 достаточно.
_Bill
Цитата(Petrooo @ Feb 12 2007, 17:31) *
Добрый день, уважаемые коллеги!
Компилятор размещает локальные переменные, определенные в теле функции либо в регистрах, либо в стеке.
Код
void Func(char Var1) {
char Var2;
...
Var2 = Var1;
...
}

Если переменная 1 или 2-х байтная, то скорее всего компилятор ее разместит в регистрах.
А мне нужно, чтобы он принудительно разместил ее (Var2) в сегменте стека.
А еще лучше, если сразу Var1 будет размещаться в стеке.
Как мне его это заставить сделать?

Попробуйте объявить ее как auto. А вообще, компилятор достаточно "умный". Он должен "увидеть" ссылку на адрес переменной и разместить ее в стеке.
Petrooo
Цитата(rezident @ Feb 13 2007, 15:30) *
ИМХО проще иметь глобальную структуру глобальных переменных. Тогда критические данные можно разместить последовательно (рядом) в такой структуре. Сохранять их в таком случае проще - всегда известно где они лежат и каков размер критической секции данных.
"Рубанули питание" для случая применения MSP430 звучит несколько странно. Если есть детектор "вырубания", то конденсатора на две-три сотни мкФ или ионистора (или литиевой батарейки на худой конец) вполне хватит чтобы завершить сохранение критически важных данных.

Как говориться, кто в лес, а кто по дрова! smile.gif
Хм, разве была речь о том, что чего там не хватит для сохранения чего то???
Агрументы самой свертки разумеется универсальны и лежат в глобальной структуре.
Но вот после того как куда-то вернулись и продолжаем рабуту дальше в "штатном режиме" по функционалу, тут уже в разных функциях по разному и универсальными глобальными структурами не опишешь. Не универсальный механизм получается, бестолково.

Цитата
"Рубанули питание" для случая применения MSP430 звучит несколько странно.

Абсолютно верно, но это только мы знаем, что проц полюбому на батарейке и что тумблером аппаратно вырубается только принтер и подсветка индикатора, а проц ушел в LPM3 smile.gif

Цитата(АДИКМ @ Feb 13 2007, 16:08) *
Скажите, а как Вы успеваете сохранится? Ведь у вас термопринтер потребляет немало...
Вы уверены, что Z или X отчет надо продолжать печатать с того же места, а не заново?

Термопринтер, индикатор разумеется вырубается сразу по тумблеру.
Коллега, не путайте: X/Z-отчет - это одно, а КЛ (контрольная лента) - это другое.
Отчеты по свертке перепечатываются заново, а печать КЛ продолжается с того чека, где зарубились (чек перепечетывается заново). Но это уже заморочки ТУ на девайс smile.gif
Цитата
А для того чтобы данные передавались как вам надо, может проще эти процедуры на ассемблере написать?

Эк, Вы куда, коллега, хватили!
Petrooo
Цитата(Dog Pawlowa @ Feb 13 2007, 16:34) *
Ну, теперь понятно smile.gif

1. Использую измерение напряжения до стабилизатора, чтобы вовремя отключить все энергопотребляющие узлы, чтобы контроллер насладился сохранением статистики в ЕЕПРОМ.
2. Чтобы статистика не попортилась, делаю это только только в критических местах.
3. Реализую алгоритм прибора в виде массива функций, а текущим индексом массива является глобальная переменная "статус".
4. Не использую стек для таких функций, но, чтобы памяти хватило, использую одни и те же глобальные переменные в каждой функции, переопределяя их каждый раз в целях соответствия имени физическому смыслу (комментарии не пишу, компенсируя это именами).

Собственно, все... После сброса контроллер инициализируется и сразу выходит на ту функцию, где он был.

Были мысли про стек, но больше риск влететь куда-то не туда, и возникает зависимость от платформы, а я это не люблю - контроллеры приходят и уходят, а люди остаются smile.gif

Извините, но ничего нового не узнал. Это все общеизвестная теория.
Кстати, если тоже немного потеоритизировать и рассмотреть случай когда контроллер не сидит на отдельной элементе питания, то записывая свертку в ЕЕПРОМ не пару байт, а поболе можно нарваться на недозапись; через год-два на уже несвежих кондерах. Свертку желательно сохранять в более быструю память. Проверено жизнью.

Меня интересует конкретика: девайс на MSP430F449; сворачиваться требуется в не одном, а в 10-ке мест (функциях); внутренний структура обрабатываемых данных во всех функциях совершенно различна.
Цитата
После сброса контроллер инициализируется и сразу выходит на ту функцию, где он был.

А откуда возмется "все то, что было нажито непосильным трудом" в каждой конткретной функции до выключения питания??? В каждом случае сохраняетесь "вручную" (пишите отдельный код в прерывании под каждый случай)?
Цитата
... и возникает зависимость от платформы, а я это не люблю - контроллеры приходят и уходят, а люди остаются

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

P.S. Коллеги, благодарю всех за отклики и ответы.

Цитата(_Bill @ Feb 13 2007, 17:08) *
Попробуйте объявить ее как auto.

Проверено. Не помогает.
Dog Pawlowa
Цитата(Petrooo @ Feb 13 2007, 19:13) *
Извините, но ничего нового не узнал. Это все общеизвестная теория.

Ну, для меня это не теория, а практика любого проекта.
Цитата(Petrooo @ Feb 13 2007, 19:13) *
Меня интересует конкретика: девайс на MSP430F449; сворачиваться требуется в не одном, а в 10-ке мест (функциях); внутренний структура обрабатываемых данных во всех функциях совершенно различна.

Меня тоже интересует конкретика, потому что не догоняю проблемы. Может, далек от специфики устройства.
Если нужно сохранять данные, то они должны быть в соответвующей структуре. Глобальной.
В чем проблема то свести данные в одно место, даже свертку подготовить, если мало времени на выключение ?
В чем смысл использования стека, если он не "шарится" между функциями, а функции складываются одна в одну, и параметры нужно сохранять? Глубина стека выросла - проще отдать это глобальным переменным, а для передачи параметров использовать переменные.
Цитата(Petrooo @ Feb 13 2007, 19:13) *
Цитата(Dog Pawlowa @ Feb 13 2007, 16:34) *

После сброса контроллер инициализируется и сразу выходит на ту функцию, где он был.

А откуда возмется "все то, что было нажито непосильным трудом" в каждой конткретной функции до выключения питания??? В каждом случае сохраняетесь "вручную" (пишите отдельный код в прерывании под каждый случай)?

Я же писал - то, что нужно после сброса для продолжения работы - в глобальных переменных. Если данные нужны и для сохранения после долгого выключения - то в буфере для сохранения в EEPROM.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.