Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18652
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

да я и сам сейчас смотрю в map-файл, и вижу, что одна :( причем если static делать в обоих модулях, то получается две. если static только в одном - одна... но если без static попробовать проинициализировать разными числами - вылетает ошибка линкера "multiple definition"... странно все это...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
pcb
Опытный кот
Сообщения: 833
Зарегистрирован: Пт авг 12, 2011 09:14:27
Откуда: Млечный путь/Земля/РФ/Екатеринбург

Re: Вопросы по С/С++ (СИ)

Сообщение pcb »

Да одна
Файлик map подцепи.

Вот
http://msdn.microsoft.com/ru-ru/library/s1sb61xd.aspx
Разработал:
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
Реклама
Аватара пользователя
ks0
Прорезались зубы
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Re: Вопросы по С/С++ (СИ)

Сообщение ks0 »

Докладываю.

"Так можно делать в С, это 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
Ум, честь и совесть. И скромность.
Сообщения: 18652
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

Страшная вещь этот Си... Чем глубже его узнаю, тем больше уверен, что его создатели без ЛСД не обошлись...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Вопросы по С/С++ (СИ)

Сообщение Gudd-Head »

А теперь суммируя всё вышеизложенное, можно по-русски и для чайников — чего-как правильно надо делать и какие могут быть подводные камни? :)
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Реклама
Аватара пользователя
GARMIN
Держит паяльник хвостом
Сообщения: 954
Зарегистрирован: Вс дек 02, 2012 16:58:33
Откуда: от туда
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение GARMIN »

Для использования глобальных переменных в разных файлах делаем так:
В файле sample.h:

Код: Выделить всё

extern char s1;
в файле main.c:

Код: Выделить всё

#include "sample.h"
char s1 = INIT_S1;
в других файлах:

Код: Выделить всё

#include "sample.h"
s1 = 2;
Указание типа с extern без присваивания -> объявление переменной в том файле, где применяете, без выделения памяти.
Указание переменной с типом и присвоением значения -> определение переменной (выделение памяти).
Использование переменной дальше без ограничений.
Лишний extern в main.c никак не мешает выделять память при определении переменной.
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18652
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

маленькое дополнение к вышесказанному: не обязательно в main.c определять эту переменную, можно в любом, лучше в том, где она реально по смыслу важна.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Вопросы по С/С++ (СИ)

Сообщение Gudd-Head »

любом.... месте?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Вопросы по С/С++ (СИ)

Сообщение menzoda »

Да, любом. Вот пример получше:

Uart.c

Код: Выделить всё

char uartTxChar;
char uartRxChar;
Uart.h

Код: Выделить всё

extern char uartTxChar;
extern char uartRxChar;
Любое место или несколько мест

Код: Выделить всё

#include "Uart.h"

//Пользуемся uartTxChar и uartRxChar
Аватара пользователя
ks0
Прорезались зубы
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Re: Вопросы по С/С++ (СИ)

Сообщение ks0 »

Вообще говоря, в принципе, эти глобальные переменные общие для нескольких модулей и основной части программы, нафиг не нужны. Без них можно легко обходится. И даже принципы объектного программирования требуют в хедере описывать только интерфейс, а данные в .с файлах. Т.е. переменные, с которыми работает модуль, описываются в модуле, можно с модификатором static, а изменяются только за счет функций, объявленных в его хедере. В современных языках C# или Java понятия глобальных переменных вообще нет. В С++ их количество сведено до минимума. В объекто-ориентированном программировании это называют инкапсуляцией, данные и детали реализации скрываются в неком "черном ящике", а наружу предоставляется только интерфейс (публичные функции).
Поэтому, не объявляйте в хедере переменные вообще никак, ни с extern, ни без, и это не будет ошибкой, а будет хорошим заделом на будущее. И как следствие не объявляйте глобальные переменные дважды в разных .c-файлах, ни с extern, ни без extern (в расчете на tentative definition).
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Вопросы по С/С++ (СИ)

Сообщение menzoda »

ks0 писал(а):В современных языках C# или Java понятия глобальных переменных вообще нет.
Воу воу воу, полегче. А как же статический класс с публичным свойством или шаблон "одиночка"? Все они представляют некое глобальное состояние, как и глобальная переменная в Си.
ks0 писал(а):Т.е. переменные, с которыми работает модуль, описываются в модуле, можно с модификатором static, а изменяются только за счет функций, объявленных в его хедере.
Не можно static, а нужно static, это является хорошим тоном, но всё же мы имеем дело с Си, поэтому...
ks0 писал(а):не объявляйте в хедере переменные вообще никак
...всё же не стоит принимать это как закон. В некоторых ситуациях глобальные переменные (как и злополучный goto кстати) могут не только упростить реализацию, но и сделать её более изящной и понятной.
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Вопросы по С/С++ (СИ)

Сообщение pokk »

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

Код: Выделить всё

u08 test(void) {
	return data;
}
Но пока не особо понимаю в чём преимущество такой передачи ? и какие могут быть ошибки если вывод из модуля делать через глобальные переменные.
Аватара пользователя
menzoda
Вымогатель припоя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Re: Вопросы по С/С++ (СИ)

Сообщение menzoda »

1. Если из модуля необходимо предоставить данные, доступные только для чтения, то в случае использования глобальной переменной кто-то может случайно изменить эту переменную, она ведь никак не защищена от записи. В этом случае использование функции (так называемого getter) не позволит записывать что-либо в эту переменную.

2. Обычно, перед передачей или чтением каких-либо данных в/из модуля, возникает необходимость некоторых действий по преобразованию данных. Например, при задании скорости работы UART может понадобиться перевести значение из бод/с в период таймера, а при чтении соответственно наоборот. Иногда может понадобиться атомарный доступ к переменной, тогда перед чтением/записью придется использовать примитивы синхронизации или запрещать прерывания. Всё это очень легко сделать если доступ осуществляется через getter и setter.

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

4. Тем не менее, мы говорим о языке C и низкоуровневом программировании, поэтому в некоторых ситуациях, когда известны все подводные камни, использование глобальных переменных может не только не навредить архитектуре приложения, но и сделать её более простой и понятной. Поэтому нельзя однозначно говорить, что глобальные переменные - зло, просто нужно использовать их с умом. В противоположность этому, новички обычно их используют везде, где надо и не надо.
Аватара пользователя
virus33
Нашел транзистор. Понюхал.
Сообщения: 175
Зарегистрирован: Пт июн 29, 2012 23:48:11

Re: Вопросы по С/С++ (СИ)

Сообщение virus33 »

Тупой вопрос. В одном коде увидел вот это:
// Банк 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; // номер прерывания
// ----------------------------------------
Вопрос один - что означает слово static, символ @ и последующее с ним значение? как я понял, это адрес в памяти, где хранится данное значение?
Аватара пользователя
slavokhire5
Прорезались зубы
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Re: Вопросы по С/С++ (СИ)

Сообщение slavokhire5 »

static обозначает то, что переменная при выходе из функции, в которой она используется, будет все равно сохраняться в памяти. т.е. под нее резервируется место "глобально". но из внешних функций эта переменная не видна. это все мое личное имхо на моем личном небогатом опыте. псевдокод:

Код: Выделить всё

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;
}
в данном случае переменная delta будет видна только из файла, в котором находится функция main, а переменная temp в цикле будет получать последовательно значения от 1 до 10.
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Вопросы по С/С++ (СИ)

Сообщение Gudd-Head »

slavokhire5 писал(а):последовательно значения от 1 до 10.
Эээ... Разве? Она не будет обнуляться при каждом вызове функции?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18652
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

не будет.
локальные static-переменные получают начальное значение единожды перед стартом main, как и все прочие (глобальные) static-переменные. при входах в функцию инициализация переменной уже не происходит, используется предыдущее значение.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Вопросы по С/С++ (СИ)

Сообщение Gudd-Head »

Хитро. А что про "@" и следущие за ней значения? Это адреса ОЗУ принудительно задаются?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Если бы было так

Код: Выделить всё

static up;
up = 0;
, то обнулялась бы, а так

Код: Выделить всё

static up = 0;
- не будет, как уже выше сказали.

Кстати, тип переменной тут не указан. Какой-то по умолчанию для static назначается (int какой-нибудь), или это всё же ошибка?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18652
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

не какой-нибудь, а самый натуральный int и назначается :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Ответить

Вернуться в «Разные вопросы по МК»