Вопросы по С/С++ (СИ)
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18655
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
да я и сам сейчас смотрю в map-файл, и вижу, что одна
причем если static делать в обоих модулях, то получается две. если static только в одном - одна... но если без static попробовать проинициализировать разными числами - вылетает ошибка линкера "multiple definition"... странно все это...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Реклама
-
pcb
- Опытный кот
- Сообщения: 833
- Зарегистрирован: Пт авг 12, 2011 09:14:27
- Откуда: Млечный путь/Земля/РФ/Екатеринбург
Re: Вопросы по С/С++ (СИ)
Разработал:
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
Re: Вопросы по С/С++ (СИ)
Докладываю.
"Так можно делать в С, это tentative definition, объект обявленный таким образом попадает в область общих данных. При линковке одноимённые объекты в этой области становятся одним объектом. В С++ так делать нельзя."
tentative definition гуглится, вопросы такого планы уже были.
Например вот.
"Так можно делать в С, это tentative definition, объект обявленный таким образом попадает в область общих данных. При линковке одноимённые объекты в этой области становятся одним объектом. В С++ так делать нельзя."
tentative definition гуглится, вопросы такого планы уже были.
Например вот.
The ANSI C standard supports the concept of the tentative definition. Any external data declaration that has no storage class specifier and no initializer is considered a tentative definition. If the identifier declared appears in a later definition, then the tentative definition is treated as if the extern storage class specifier were present. In other words, the tentative definition becomes a simple referencing declaration.
If the end of the translation unit is reached and no definition has appeared with an initializer for the identifier, then the tentative definition becomes a full definition, and the object defined has uninitialized (zero-filled) space reserved for it.
Unlike ANSI C, C++ doesn't have the concept of a tentative declaration; an external data declaration without a storage class specifier is always a definition.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18655
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Страшная вещь этот Си... Чем глубже его узнаю, тем больше уверен, что его создатели без ЛСД не обошлись...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Вопросы по С/С++ (СИ)
А теперь суммируя всё вышеизложенное, можно по-русски и для чайников — чего-как правильно надо делать и какие могут быть подводные камни? 
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Реклама
- GARMIN
- Держит паяльник хвостом
- Сообщения: 954
- Зарегистрирован: Вс дек 02, 2012 16:58:33
- Откуда: от туда
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Для использования глобальных переменных в разных файлах делаем так:
В файле sample.h:
в файле main.c:
в других файлах:
Указание типа с extern без присваивания -> объявление переменной в том файле, где применяете, без выделения памяти.
Указание переменной с типом и присвоением значения -> определение переменной (выделение памяти).
Использование переменной дальше без ограничений.
Лишний extern в main.c никак не мешает выделять память при определении переменной.
В файле sample.h:
Код: Выделить всё
extern char s1;Код: Выделить всё
#include "sample.h"
char s1 = INIT_S1;Код: Выделить всё
#include "sample.h"
s1 = 2;Указание переменной с типом и присвоением значения -> определение переменной (выделение памяти).
Использование переменной дальше без ограничений.
Лишний extern в main.c никак не мешает выделять память при определении переменной.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18655
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
маленькое дополнение к вышесказанному: не обязательно в main.c определять эту переменную, можно в любом, лучше в том, где она реально по смыслу важна.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Вопросы по С/С++ (СИ)
любом.... месте?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Re: Вопросы по С/С++ (СИ)
Да, любом. Вот пример получше:
Uart.c
Uart.h
Любое место или несколько мест
Uart.c
Код: Выделить всё
char uartTxChar;
char uartRxChar;
Код: Выделить всё
extern char uartTxChar;
extern char uartRxChar;
Код: Выделить всё
#include "Uart.h"
//Пользуемся uartTxChar и uartRxChar
Re: Вопросы по С/С++ (СИ)
Вообще говоря, в принципе, эти глобальные переменные общие для нескольких модулей и основной части программы, нафиг не нужны. Без них можно легко обходится. И даже принципы объектного программирования требуют в хедере описывать только интерфейс, а данные в .с файлах. Т.е. переменные, с которыми работает модуль, описываются в модуле, можно с модификатором static, а изменяются только за счет функций, объявленных в его хедере. В современных языках C# или Java понятия глобальных переменных вообще нет. В С++ их количество сведено до минимума. В объекто-ориентированном программировании это называют инкапсуляцией, данные и детали реализации скрываются в неком "черном ящике", а наружу предоставляется только интерфейс (публичные функции).
Поэтому, не объявляйте в хедере переменные вообще никак, ни с extern, ни без, и это не будет ошибкой, а будет хорошим заделом на будущее. И как следствие не объявляйте глобальные переменные дважды в разных .c-файлах, ни с extern, ни без extern (в расчете на tentative definition).
Поэтому, не объявляйте в хедере переменные вообще никак, ни с extern, ни без, и это не будет ошибкой, а будет хорошим заделом на будущее. И как следствие не объявляйте глобальные переменные дважды в разных .c-файлах, ни с extern, ни без extern (в расчете на tentative definition).
Re: Вопросы по С/С++ (СИ)
Воу воу воу, полегче. А как же статический класс с публичным свойством или шаблон "одиночка"? Все они представляют некое глобальное состояние, как и глобальная переменная в Си.ks0 писал(а):В современных языках C# или Java понятия глобальных переменных вообще нет.
Не можно static, а нужно static, это является хорошим тоном, но всё же мы имеем дело с Си, поэтому...ks0 писал(а):Т.е. переменные, с которыми работает модуль, описываются в модуле, можно с модификатором static, а изменяются только за счет функций, объявленных в его хедере.
...всё же не стоит принимать это как закон. В некоторых ситуациях глобальные переменные (как и злополучный goto кстати) могут не только упростить реализацию, но и сделать её более изящной и понятной.ks0 писал(а):не объявляйте в хедере переменные вообще никак
Re: Вопросы по С/С++ (СИ)
Здравствуйте, помню что где-то тут было обсуждения на тему что вместо глобальный переменных для передачи параметра из одного модуля в другой лучше использовать функции. что-то типа такого
Но пока не особо понимаю в чём преимущество такой передачи ? и какие могут быть ошибки если вывод из модуля делать через глобальные переменные.
Код: Выделить всё
u08 test(void) {
return data;
}Re: Вопросы по С/С++ (СИ)
1. Если из модуля необходимо предоставить данные, доступные только для чтения, то в случае использования глобальной переменной кто-то может случайно изменить эту переменную, она ведь никак не защищена от записи. В этом случае использование функции (так называемого getter) не позволит записывать что-либо в эту переменную.
2. Обычно, перед передачей или чтением каких-либо данных в/из модуля, возникает необходимость некоторых действий по преобразованию данных. Например, при задании скорости работы UART может понадобиться перевести значение из бод/с в период таймера, а при чтении соответственно наоборот. Иногда может понадобиться атомарный доступ к переменной, тогда перед чтением/записью придется использовать примитивы синхронизации или запрещать прерывания. Всё это очень легко сделать если доступ осуществляется через getter и setter.
3. Даже если сейчас ничего из вышеперечисленного не требуется, то это может потребоваться в будущем. При использовании функций можно будет просто добавить в них требуемый функционал, снаружи интерфейс модуля останется прежним. Иначе, изменения в интерфейсе модуля потребуют изменений во всех местах, где он используется. То есть в данном случае с помощью функций доступа мы скрываем внутреннюю реализацию модуля и все особенности его работы, это называется инкапсуляция.
4. Тем не менее, мы говорим о языке C и низкоуровневом программировании, поэтому в некоторых ситуациях, когда известны все подводные камни, использование глобальных переменных может не только не навредить архитектуре приложения, но и сделать её более простой и понятной. Поэтому нельзя однозначно говорить, что глобальные переменные - зло, просто нужно использовать их с умом. В противоположность этому, новички обычно их используют везде, где надо и не надо.
2. Обычно, перед передачей или чтением каких-либо данных в/из модуля, возникает необходимость некоторых действий по преобразованию данных. Например, при задании скорости работы UART может понадобиться перевести значение из бод/с в период таймера, а при чтении соответственно наоборот. Иногда может понадобиться атомарный доступ к переменной, тогда перед чтением/записью придется использовать примитивы синхронизации или запрещать прерывания. Всё это очень легко сделать если доступ осуществляется через getter и setter.
3. Даже если сейчас ничего из вышеперечисленного не требуется, то это может потребоваться в будущем. При использовании функций можно будет просто добавить в них требуемый функционал, снаружи интерфейс модуля останется прежним. Иначе, изменения в интерфейсе модуля потребуют изменений во всех местах, где он используется. То есть в данном случае с помощью функций доступа мы скрываем внутреннюю реализацию модуля и все особенности его работы, это называется инкапсуляция.
4. Тем не менее, мы говорим о языке C и низкоуровневом программировании, поэтому в некоторых ситуациях, когда известны все подводные камни, использование глобальных переменных может не только не навредить архитектуре приложения, но и сделать её более простой и понятной. Поэтому нельзя однозначно говорить, что глобальные переменные - зло, просто нужно использовать их с умом. В противоположность этому, новички обычно их используют везде, где надо и не надо.
Re: Вопросы по С/С++ (СИ)
Тупой вопрос. В одном коде увидел вот это:
Вопрос один - что означает слово static, символ @ и последующее с ним значение? как я понял, это адрес в памяти, где хранится данное значение?// Банк 0 [0x0020 - 0x006F]
static volatile unsigned int adcP0 @ 0x24; // результат АЦП0
static volatile unsigned char adcP0L @ 0x24; // результат АЦП0 младший
static volatile unsigned char adcP0H @ 0x25; // результат АЦП0 старший
static volatile unsigned int num @ 0x26; // ширина импульса
static volatile unsigned char numL @ 0x26; // ширина импульса младший
static volatile unsigned char numH @ 0x27; // ширина импульса старший
static volatile unsigned char nserv @ 0x2A; // номер прерывания
// ----------------------------------------
- slavokhire5
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Пн сен 26, 2011 13:48:25
- Откуда: Харьков
Re: Вопросы по С/С++ (СИ)
static обозначает то, что переменная при выходе из функции, в которой она используется, будет все равно сохраняться в памяти. т.е. под нее резервируется место "глобально". но из внешних функций эта переменная не видна. это все мое личное имхо на моем личном небогатом опыте. псевдокод:
в данном случае переменная delta будет видна только из файла, в котором находится функция main, а переменная temp в цикле будет получать последовательно значения от 1 до 10.
Код: Выделить всё
static delta = 10;
void main (void)
{
uint8_t temp;
for (uint8_t i = 0; i < 10; i++) {
temp = up();
}
}
uint8_t up (void) {
static up = 0;
up++;
return up;
}Осилит дорогу идущий
--------------------------
Пишу на Си за еду
--------------------------
Пишу на Си за еду
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Вопросы по С/С++ (СИ)
Эээ... Разве? Она не будет обнуляться при каждом вызове функции?slavokhire5 писал(а):последовательно значения от 1 до 10.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18655
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
не будет.
локальные static-переменные получают начальное значение единожды перед стартом main, как и все прочие (глобальные) static-переменные. при входах в функцию инициализация переменной уже не происходит, используется предыдущее значение.
локальные static-переменные получают начальное значение единожды перед стартом main, как и все прочие (глобальные) static-переменные. при входах в функцию инициализация переменной уже не происходит, используется предыдущее значение.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Вопросы по С/С++ (СИ)
Хитро. А что про "@" и следущие за ней значения? Это адреса ОЗУ принудительно задаются?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Если бы было так, то обнулялась бы, а так - не будет, как уже выше сказали.
Кстати, тип переменной тут не указан. Какой-то по умолчанию для static назначается (int какой-нибудь), или это всё же ошибка?
Код: Выделить всё
static up;
up = 0;Код: Выделить всё
static up = 0;Кстати, тип переменной тут не указан. Какой-то по умолчанию для static назначается (int какой-нибудь), или это всё же ошибка?
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18655
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
не какой-нибудь, а самый натуральный int и назначается 
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!


