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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение 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

Сообщение ks0 »

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

Сообщение menzoda »

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

Сообщение pokk »

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

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

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

Сообщение menzoda »

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

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

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

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

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

Сообщение 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.
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
Друг Кота
Аватара пользователя
Сообщения: 20117
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

Сообщение ARV »

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

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

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

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

Сообщение WiseLord »

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

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

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

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

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

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

Сообщение ARV »

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

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

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

WiseLord писал(а):Если бы было так

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

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

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

static up = 0;
- не будет, как уже выше сказали.
Всё чудесатей и чудесатей :)
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

По поводу "@" - думаю, это какой-то атрибут, возможно специфический для какой-то архитектуры (а не вообще для языка C). Что-то наподобие "_at_" здесь.
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 535
Зарегистрирован: Вт авг 28, 2012 22:21:33

Сообщение menzoda »

Gudd-Head писал(а):Всё чудесатей и чудесатей
Так, вы тут Gudd-Head давайте не путайте, обнуляется не обнуляется.

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

Хотя я сейчас посмотрел стандарт C99 и там написано, что static инициализируется перед запуском программы, а не при первом вызове функции. Перепутал с C#.
Последний раз редактировалось menzoda Чт окт 09, 2014 13:15:55, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ

Сообщение просто КОТ »

Друзья, есть маленький вопрос и большая проблема. Я программист всего месяца полтора как. Если не меньше... Надо мне отправить строку следующего вида: L=xx /n. Где хх это содержимое переменной light.
Спойлер

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

#include "stdio.h"
char res[8];


/********Тут**по***идее**код*************/

if(send) {  
			sprintf (res, "%s %d", "L=", light);  
        	Out_Str(res); mUart_Putch(0x0D);
			send=0;
}
Функция Out_Str отправляет строку и работает железно. Но вот сама строка не формируется никак. Код без этих шести строк занимал 37% памяти и работал чётко. Дописав их к основному коду получил 114% памяти и собственно кучу глюков. Вопрос -- что не так, и как быть?
Спойлер

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

#define 	F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include "mUart.h"
#include "stdio.h"

char light = 1;
char b = 1;
char res[8];
/****************************************************************/


volatile unsigned char   tx_fl=0;
volatile unsigned char   TSK_CLR=0;
volatile unsigned char   ID=83;

volatile unsigned char rx;
volatile unsigned char rx_buf[10];
volatile unsigned char rx_cnt=0;
volatile unsigned char rx_fl=0;
volatile unsigned char rx_size;
volatile unsigned char err=0;
volatile unsigned char send=0;


/****************************************************************/
/*                       Ñäåëàòü çàìåð ôîòîäàò÷èêà                         */
/****************************************************************/

ISR (TIM1_OVF_vect)  {
if(ADCH > 0x63 && b < 6) b++;
if(ADCH < 0x63 && b > 0) b--;
	light = 16*b + 1;
	ADCSRA|= (1<<ADSC);
	send=1;
}
/****************************************************************/
/*                       Ïðèíÿò áàéò                            */
/****************************************************************/
void CallBack_RX(char ch){

rx=ch;

if(err)   return;

rx_buf[rx_cnt]=ch;

if(ch==13){     // '/n'
    rx_fl=1;
    rx_size = rx_cnt;
    rx_cnt=0;
    return;
}

if(++rx_cnt>=sizeof(rx_buf)){
    err=1;
    rx_cnt=0;
}

}
/****************************************************************/
/*                       Áàéò îòïðàâëåí                         */
/****************************************************************/
void CallBack_TX(void){

tx_fl=1;


}


/****************************************************************/
void Out_Str(char* s){
  while(*s){
    tx_fl=0;
    mUart_Putch(*s++);
    while(!tx_fl);
  };
}
/****************************************************************/

int main (void){

    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
	DDRB = 0x03; 
    MCUCR = (0<<ISC01) | (1<<ISC00); 
	OCR1AH= 0xFF;
	OCR1AL= 0xFF;
    TCCR1B|=(1<<CS10)|(1<<CS12); // Çàïóñòèëè ÑÒÑ.
    TIMSK1|=(1<<TOIE1); // Ðàçðåøàåì ïðåðûâàíèå ïî ñîâïàäåíèþ.
	ADMUX=0x05; // ÀÖÏ íà ïÿòûé âõîä
	ADCSRB|=(1<<ADLAR);
	ADCSRA|=(1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
	ADCH = 20;
    sei();
	mUart_Init();


while (1) {

if(err) {    // Bufer overflow
            err=0;
            // Send error message 
}
if(send) {  
			sprintf (res, "%s %d", "L=", light);  
        	Out_Str(res); mUart_Putch(0x0D);
			send=0;
}
}
}
Изображение
И ты врёшь!!! © Vladisman
Изображение
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 20117
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

просто КОТ писал(а):Вопрос -- что не так
Да всё так. Sprintf занимает дофига места.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Друг Кота
Аватара пользователя
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ

Сообщение просто КОТ »

Ладненько, тогда к вопросу нумер два. Как быть?
Изображение
И ты врёшь!!! © Vladisman
Изображение
Контактная информация:
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Банально itoa() использовать
Друг Кота
Аватара пользователя
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ

Сообщение просто КОТ »

Эм... Википедия сказала, что itoa принимает передаваемое целое число input и конвертирует его в число в основании корня radix. Полученное число (последовательность цифр основания radix) записывается в буфер вывода buffer. И я это совсем не понял. Какой корень, какое основание?
Изображение
И ты врёшь!!! © Vladisman
Изображение
Контактная информация:
Ответить

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