Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: static variable
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Jenya7
Зачем локальную переменную делать статик? Если мы сохраняем ее в RAM то с тем же успехом ее можно сделать глобальной ну или статик на уровне файла.
Baser
Цитата(Jenya7 @ Apr 3 2016, 12:40) *
с тем же успехом ее можно сделать глобальной ну или статик на уровне файла.

Для ограничения области видимости статической переменной внутри функции.
В других местах можно применять переменные с таким же именем и они будут другими для компилятора.
Jenya7
Цитата(Baser @ Apr 3 2016, 16:31) *
Для ограничения области видимости статической переменной внутри функции.
В других местах можно применять переменные с таким же именем и они будут другими для компилятора.

я понял. спасибо. наверное когда нибудь мне пригодиться такое свойство.
Baser
При "правильном" программировании все статические переменные, которые применяются только внутри функции, нужно обязательно объявлять внутри этой функции.
Например, переменная step, которая является текущим шагом конечного автомата, описываемого функцией.
Это повышает читабельность кода и снижает возможность ошибок.
Нельзя случайно изменить эту переменную в другой функции и не нужно рыться по всему проекту, выясняя где эта переменная еще используется.
Jenya7
спасибо. наконец то понял для чего это нужно. sm.gif
adnega
Цитата(Baser @ Apr 3 2016, 17:38) *
При "правильном" программировании

Но такой подход убивает чистоту функции, а в некоторых языках программирования чистота функции большой плюс.
Функцию с внутренней переменной step не особенно запихнешь в библиотеку для повторного использования.
С многопоточностью будут проблемы у такой функции.
Совпадение имен глобальной и локальной переменной тоже лучше не практиковать - попутать что где легче простого.
dxp
QUOTE (adnega @ Apr 4 2016, 12:22) *
Но такой подход убивает чистоту функции, а в некоторых языках программирования чистота функции большой плюс.
Функцию с внутренней переменной step не особенно запихнешь в библиотеку для повторного использования.
С многопоточностью будут проблемы у такой функции.

Ну, с глобальной переменной будет ровно то же самое. Что касается полезности, то завит от. У локальных статических функций есть свои плюсы. Например, функции-генераторы. Или тот же синглтон Мейерса. Реализация получается простая и эффективная. Конечно, в любом случае программист должен чётко представлять, что он делает и какие последствия могут возникнуть из-за неправильного использования.

QUOTE (adnega @ Apr 4 2016, 12:22) *
Совпадение имен глобальной и локальной переменной тоже лучше не практиковать - попутать что где легче простого.

Это да. К слову, глобальных переменных нужно стараться избегать, во всяком случае, минимизировать их количество.
adnega
Цитата(dxp @ Apr 5 2016, 07:55) *
Ну, с глобальной переменной будет ровно то же самое.

А если все необходимые переменные передавать в функцию (в виде списка или сложного объекта)?
Разумеется, что совсем без побочных действий не обойтись, но если данные можно отделить от кода,
то я такой возможностью пользуюсь.
Тут пример для управления шаговым двигателем приводили. Предложенная реализация возможна
для одного двигателя, а если их много больше?
Я бы сделал массив объектов, которые бы хранили все необходимое - и текущий шаг, и скорость, и ускорение,
и целевое значение, обратную связь по энкодеру или потенциометру, адреса пинов, если это необходимо.
А функцию, решающую что делать с полем step, сделал бы универсальной.
Разумеется static переменных в ней не было бы. Оформил бы это в виде библиотеки и таскал из проекта в проект,
где есть хоть один шаговый двигатель.
Сергей Борщ
Цитата(adnega @ Apr 5 2016, 10:04) *
Разумеется static переменных в ней не было бы.
Все это хорошо, но локальные данные могут быть и константными (скажем, таблица для перевода номера микрошага в коэф. заполнения ШИМ или любые другие константы) и чтобы эти данные не копировались в ОЗУ во время создания переменной при каждом входе в такую функцию, переменная должна быть объявлена статической.
adnega
Цитата(Сергей Борщ @ Apr 5 2016, 11:52) *
скажем, таблица для перевода номера микрошага в коэф. заполнения ШИМ

Т.е. эта таблица жестко "вшита" в функцию? Не пойдет ибо ШИМ довольно аппаратно-зависимая вещь.
Хотя идея понятна (может понадобиться таблица синуса, например).
Baser
Цитата(adnega @ Apr 4 2016, 09:22) *
Но такой подход убивает чистоту функции, а в некоторых языках программирования чистота функции большой плюс.
С многопоточностью будут проблемы у такой функции.

С этим никто не спорит, но нужно решать в каждом конкретном случае, как будет удобней.

Цитата
Функцию с внутренней переменной step не особенно запихнешь в библиотеку для повторного использования.

А вот тут никто вам не запрещает это делать. Более того, в стандартных библиотеках Си полно функций с таким финтом,
в описаниях отдельно пишут, что они "опасные", не реентерабельные, дописывают новые варианты безопасных, но нестандартных функций. Но стандартные функции то уже никуда не денешь sm.gif
Вот пример, функция парсинга текстовых строк strtok

Цитата
Совпадение имен глобальной и локальной переменной тоже лучше не практиковать - попутать что где легче простого.

Одинаковые глобальные и локальные переменные тоже не советую применять.
А вот одинаковые локальные и статические внутри функций - очень даже можно применять.

Цитата(adnega @ Apr 5 2016, 11:04) *
А если все необходимые переменные передавать в функцию (в виде списка или сложного объекта)?

Такой подход тоже имеет место быть, когда есть несколько одинаковых кусков кода обработки.

Цитата(Сергей Борщ @ Apr 5 2016, 11:52) *
Все это хорошо, но локальные данные могут быть и константными (скажем, таблица для перевода номера микрошага в коэф...

Для таблиц и констант можно применять указатели, которые тоже передаются в функцию. Можно передавать также и переменные свойства таблиц (длину, структуру).

Много чего можно придумать, главное чтобы понятность кода не страдала.
А то сам иногда так накручу код для компактности, потом смотрю на тот ужОс, который получился и понимаю, что написание "тупо в лоб методом copy-paste" было бы лучше sm.gif
Сергей Борщ
Цитата(Baser @ Apr 5 2016, 12:13) *
Для таблиц и констант можно применять указатели, которые тоже передаются в функцию.
Порой проще и естественней засунуть таблицу в функцию. Например, таблицу перекодировки тетрады в ASCII для вывода чисел в шестнадцатиричном формате. Такая таблица больше нигде не понадобится, какой смысл ее выностить из функции?
Цитата(Baser @ Apr 5 2016, 12:13) *
А то сам иногда так накручу код для компактности, потом смотрю на тот ужОс, который получился и понимаю, что написание "тупо в лоб методом copy-paste" было бы лучше sm.gif
Серега, ты созрел для перехода на C++ sm.gif
Baser
Цитата(Сергей Борщ @ Apr 5 2016, 13:48) *
Серега, ты созрел для перехода на C++ sm.gif

Увы, все никак...
Даже осилил почти весь учебник Шилдса, но до конца прочуствовал только одну фразу во введении,
где говорится, что смысл применять плюсы есть только начиная с определенного уровня сложности проектов.

У меня проекты сравнительно простые, поэтому я никак не пойму для чего мне все эти фантики (обертки) которые скрывают реальную сущность объектов.
С переходом с асма на си было все понятно, выгоды очевидны, а тут... laughing.gif
esaulenka
Цитата(Baser @ Apr 5 2016, 15:08) *
где говорится, что смысл применять плюсы есть только начиная с определенного уровня сложности проектов.


Да что этот Шилдс понимает... :-)
Я осваивал плюсы на scmRTOS ("кишки" довольно сложные, но снаружи всё просто и понятно) и на Qt (супер-понятный внешний интерфейс, в "кишки" даже не лазил).
Рекомендую!
После этого свои классы без особых проблем придумываются.

При этом проекты не сказать, чтоб прямо сложные. Пара сотен килобайт исходников - это немного совсем...
zltigo
QUOTE (Сергей Борщ @ Apr 5 2016, 13:48) *
...созрел для перехода на C++ sm.gif

Мой первый сиобразный язык был С++, а не С. В незапамятные времена, когда только появился первый (первый, потому, что 1.0 версии не было sm.gif ) борлондячий Борланд С++ 2.0 я получил персональный компьютер и решил сваять для работы некую приблуду для которой требовалась, то, что я назвал, "оконной библиотекой" - то есть всякие окошки, текстовые естественно, но все же типа "Windows". В КБ у меня уже был уже бывалый сишный программисто, который утверждал, что писать нужно на Си с большими вкраплениями ASM, иначе будет безумно медленно. В обшем-то он был прав, поскольку тогдашний массовый персональный компьютер был восьмибитовым и имел тактовую 4,7MHz sm.gif. Он даже взялся на спор показать мастеркласс в соревновании на скорость работы оконной библиотеки. В общем вечерами сидели и писали. Я на плюсах, правда с вкрапелениями на ASM, ибо уровень оптимизации тогдашних компиляторов был просто никакой, он на Си. Результат был как бы неожиданный - плюсовая работала быстрее sm.gif. Причина на самом деле проста - уже больно она красиво и хорошо ложилась она во все эти классы и иже с ними. Выигрыш был за счет лучшей системной оптимизации. На самом деле обе , библиотеки работали медленно sad.gif. Так что дальше начался этап писания на Си, но опираясь на понимание пришедшее с плюсов. Компиляторы с тех пор сделали громадный скачек так что СЕГОДНЯ откатываться на Си уже не пришлось-бы.
Сегодня надо писать на C++, хотя я так и остался де-факто на Си. Но С++ подход к делу НАВСЕГДА остался со мной.
Baser
Цитата(esaulenka @ Apr 7 2016, 10:03) *
При этом проекты не сказать, чтоб прямо сложные. Пара сотен килобайт исходников - это немного совсем...

Цитата(zltigo @ Apr 7 2016, 10:35) *
некую приблуду для которой требовалась, то, что я назвал, "оконной библиотекой" - то есть всякие окошки, текстовые естественно, но все же типа "Windows"

Вот я и говорю, что проекты слишком малы для плюсов - я в основном ваяю различные интеллектуальные датчики и небольшие платы управления. До сотни килобайт еще не добирался sm.gif

Вот начал делать один прибор уже с графическим дисплеем, там да, уже чувствуется необходимость увеличения абстракции верхнего уровня софта.
Так что 100 КБайт кода - это по моим ощущением и есть примерная граница необходимости качественного скачка sm.gif
Сергей Борщ
Я и мигалку светодиодов на плюсах пишу. В общем, с упомянутм мнением дядьки Шилдта в корне не согласен.
dxp
QUOTE (Сергей Борщ @ Apr 7 2016, 16:49) *
Я и мигалку светодиодов на плюсах пишу. В общем, с упомянутм мнением дядьки Шилдта в корне не согласен.

+1. Дело не в объёме, а в подходе, в другом ощутительном состоянии, когда используешь С++. Кстати, это состояние можно испытывать и при сугубо сишном подходе (о чём выше сказано), но на плюсах это достигается проще, без помех.
Сергей Борщ
может быть дядька Шилдт имел ввиду объектно-ориентированный подход, а не сам язык С++, который к объектно-ориентированному подходу достаточно перпендикулярен?
Я не понимаю, что может мешать в программе класса "мигалка светодиодом" использовать перегрузку операторов:
CODE
void print(char const * string);
void print(int number);

void test()
{
    print("I = ");
    print(123);
}
// вместо дающего точно такой же выходной код сишного
void print_string(char const * string);
void print_number(int number);

void test()
{
    print_string("I = ");
    print_number(123);
}

что мешает объявлять типы структур более короткой записью, без typedef:
CODE
struct a_t
{
    int B;
    int C;
};
a_t A;

// вместо дающего точно такой же выходной код сишного
typedef struct
{
    int B;
    int C;
} a_t;
a_t A;

что мешает использовать шаблоны
CODE
void send(void const * from, size_t size);

template<typename T>
inline void send(T & data) { send(&data, sizeof(data)); }

uint32_t A;
uint8_t B;
struct c_t { uint32_t A; uint8_t B; char Name[20]; } C;

void test()
{
    send(A);
    send(B);
    send(C);
}

// вместо дающего точно такой же выходной код сишного
void test1()
{
    send(&A, sizeof(A));
    send(&B, sizeof(B));
    send(&C, sizeof(C));
}

что мешает использовать объявления структур внутри структур
CODE
struct config_t
{
   struct module_a_t
   {
       ....
   };
   struct module_b_t
   {
      ....
   };
   module_a_t A;
   module_b_t B;
} Config;

config::module_a_t * pModule_A_cfg = &Config.A;
// вместо дающего точно такой же выходной код сишного
typedef struct
{
   ....
} module_a_config_t;
typedef struct
{
    ....
} module_b_config_t;
typedef struct
{
   module_a_config_t A;
   module_b_config_t B;
} config_t;
config_t Config;

module_a_config_t * pModule_A_cfg = &Config.A;


что мешает использовать хотя бы простейшие объекты?
CODE
class a_t
{
public:
    void do_process();
private
    ... какие-то данные ....    
}
a_t A, B;
void test()
{
    A.do_process();
    B.do_process();
}

// вместо дающего точно такой же выходной код сишного
typedef struct
{
    ... какие-то данные ....    
} a_t;
a_t A, B;
void do_process(a_t * data);

void test()
{
    do_process(&A);
    do_process(&B);
}


и таких примеров можно привести великое множество. Еще раз подчеркиваю - эти исходники дают абсолютно идентичный выходной код, но на С++ они короче, а значит их легче писать, в них труднее запутаться или допустить описку.
ViKo
По-моему, в С так же можно использовать структуры, как и в С++.
Из приведенных выше примеров привлекает полиморфизм.
А до классов надо еще дорасти. У меня сотни функций, в какие объекты их пихать?
Сергей Борщ
QUOTE (ViKo @ Apr 8 2016, 11:00) *
По-моему, в С так же можно использовать структуры, как и в С++.
Покажите, как сделать такое:
CODE
struct config_t
{
   struct module_a_t
   {
       ....
   };
   struct module_b_t
   {
      ....
   };
   module_a_t A;
   module_b_t B;
} Config;

Как это делается в Сях я показал, там больше писанины и нет сокрытия имен.
QUOTE (ViKo @ Apr 8 2016, 11:00) *
Из приведенных выше примеров привлекает полиморфизм.
В приведенных выше примерах полиморфизма не было. Полиморфизм - это уже объектно-ориентированное программирование.
QUOTE (ViKo @ Apr 8 2016, 11:00) *
А до классов надо еще дорасти. У меня сотни функций, в какие объекты их пихать?
Пихайте куда угодно (сколько информации в вопросе - столько и в ответе).
Ваши функции не используют данные? Если используют - имеет смысл их логически объединить. функция + данные - это уже класс. а если несколько функций используют некоторую общую часть данных - напрашивается структура классов, где базовый работает с общей частью данных, а наследники - с общими данными через базовый класс и со своими личными данными - каждый по-своему.

P.S. Если кто-то смотрел исходник openOCD - там полиморфизм реализован на чистых Сях. Это тихий ужас и закат солнца вручную.
ViKo
А как называется свойство, когда функции с одинаковым именем работают с разными типами данных?
zltigo
QUOTE (ViKo @ Apr 8 2016, 14:33) *
А как называется свойство, когда функции с одинаковым именем работают с разными типами данных?

Перегрузка функций.



QUOTE (Сергей Борщ @ Apr 8 2016, 13:28) *
Покажите, как сделать такое:
CODE
struct config_t
{
   struct module_a_t
   {
       ....
   };
   struct module_b_t
   {
      ....
   };
   module_a_t A;
   module_b_t B;
} Config;


Так:

CODE
typedef struct config_t
{
   struct
   {
....
   }A;
   struct
   {
....
    }B;
} Config;


QUOTE
в Сях я показал, там больше писанины и нет сокрытия имен.

Писанины в Сях оказалось меньше, а имена вообще отсутствуют за ненадобностью sm.gif.
Baser
Цитата(Сергей Борщ @ Apr 8 2016, 11:45) *
может быть дядька Шилдт имел ввиду объектно-ориентированный подход, а не сам язык С++, который к объектно-ориентированному подходу достаточно перпендикулярен?
Я не понимаю, что может мешать в программе класса "мигалка светодиодом" использовать перегрузку операторов:
что мешает объявлять типы структур более короткой записью, без typedef:
что мешает использовать шаблоны
что мешает использовать объявления структур внутри структур
что мешает использовать хотя бы простейшие объекты?

и таких примеров можно привести великое множество. Еще раз подчеркиваю - эти исходники дают абсолютно идентичный выходной код, но на С++ они короче, а значит их легче писать, в них труднее запутаться или допустить описку.

Тут я могу ответить только за себя - применять эти небольшие улучшения/расширения си, конечно можно, но я не вижу качественного улучшения. Поэтому и не применяю, тем более что накопилось много долгоиграющих проектов на разных МК под разными компиляторами, которые периодически нужно подкручивать и кидать куски кода туда-сюда. ANSI C поддерживает весь зоопарк применяемых мною инстументов, а вот плюсы - увы...
Тем более, что ошибки/опечатки в аналогах всех вышеупомянутых улучшений хорошо отлавливаются компиляторами и тут проблем нет.

А применение объектно-ориентированного подхода это уже отдельный вопрос и к вышеприведенным примерам отношения не имеющий, и на маленьких проектах ИМХО себя не оправдывающий.
Сергей Борщ
QUOTE (zltigo @ Apr 8 2016, 13:47) *
Писанины в Сях оказалось меньше, а имена вообще отсутствуют за ненадобностью sm.gif.
И как теперь объявить указатель на структуру А?
zltigo
QUOTE (Сергей Борщ @ Apr 8 2016, 15:52) *
И как теперь объявить указатель на структуру А?

Не понял. Ты же хотел скрыть имена? Вот они и "скрыты". И вообще, что такое указатель на струкруру внутри структуры без использования наружной структуры? На кой он может быть нужен?

Можешь написать на базе своего-же сишного примера, для чего это такое? В чем цимус:
a = &c.A;
a->x;
перед
s = &c;
s->A.x;

Тем более, что ценой нескольких слов typedef в хидре можно и в Си так-же получать доступ.
Только вот от паковки структуры с таким доступом будет снос крыши.

P.S.
Если бы С++ структуры давали хоть сколь-нибудь существенное преимущество перед возможностями С99, то я бы при своей любви к описанию данных, уже точно писал на С++.
Сергей Борщ
QUOTE (zltigo @ Apr 8 2016, 15:26) *
Не понял. Ты же хотел скрыть имена? Вот они и "скрыты".
Они не то чтобы скрыты - это структуры безымянного типа. Плюсы позволяют иметь типы с именами, но при этом не засоряющие глобальную область видимости.

QUOTE (zltigo @ Apr 8 2016, 15:26) *
И вообще, что такое указатель на струкруру внутри структуры без использования наружной структуры? На кой он может быть нужен?
Кто сказал, что без использования наружной? Выше был пример: есть наружная структура - глобальный конфиг системы. Она состоит из конфигов конкретных составляющих систему модулей. Работая с конфигом конкретного модуля удобно получить указатель (или ссылку, такого в голых Сях вообще нет) на конфиг конкретного модуля (выше показывал: config::module_a_t * pModule_A_cfg = &Config.A; или еще проще: auto pModule_A_cfg = &Config.A;). При этом в глобальной области видимости у меня только один тип - config_t.

QUOTE (zltigo @ Apr 8 2016, 15:26) *
Если бы С++ структуры давали хоть сколь-нибудь существенное преимущество перед возможностями С99, то я бы при своей любви к описанию данных, уже точно писал на С++.
"Ты видишь суслика? А он есть!". Наследование, объявление типов и функций внутри структур - весьма существенное преимущество.
zltigo
QUOTE
"Ты видишь суслика? А он есть!". Наследование, объявление типов и функций внутри структур - весьма существенное преимущество.


QUOTE (Сергей Борщ @ Apr 8 2016, 16:45) *
При этом в глобальной области видимости у меня только один тип - config_t.

Если ограничение глобальной видимости и неиспользование typedef это единственное практически извлекаемое из всего этого преимущество, то оно меня не слишком восхитило sad.gif.
ViKo
Цитата(Сергей Борщ @ Apr 8 2016, 13:28) *
В приведенных выше примерах полиморфизма не было. Полиморфизм - это уже объектно-ориентированное программирование.

И Шилдт в "Полном справочнике по С++" (гл. 11), и Википедия сообщают, что перегрузка функций является формой полиморфизма.
https://ru.wikipedia.org/wiki/%D0%9F%D0%B5%...%86%D0%B8%D0%B9
https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%...B8%D0%BA%D0%B0)
Сергей Борщ, "поздравляю... вы неправы.
Herz
Господа! Напоминаю, тема была открыта совсем не для сравнения С с С++.
Поскольку ответ на вопрос автора получен, тему закрыл во избежание очередного холивара.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.