Как изменить правила применения define препроцессора ?

starcomputer
Offline
Зарегистрирован: 19.10.2021

По умолчанию #define не долно начинаться на цифру, а также, как оказалось ругается, если первой стоит русская буква.

Можно как-то изменить правила ?

Собственно хочется заставить работать вот это:

#define А \x80 // А - русская


Arduino: 1.8.16 (Windows 7), Плата:"Arduino Due (Programming Port)"
defines.h:112:9: error: macro names must be identifiers
exit status 1
macro names must be identifiers
 
b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Можно как-то изменить правила ?

нет

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Дурацкий вопрос можно? Нахуа?

b707
Offline
Зарегистрирован: 26.05.2017

Rumata пишет:

Дурацкий вопрос можно? Нахуа?

ну как нахуа? что бы писать МАМА. а не набивать это кодами :)

Правда это решается проще - выбором правильной кодировки в ИДЕ

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Ясно. Извиняюсь, протупил! Я еще просто не дорос до задач такого уровня :)

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Собственно хочется заставить работать вот это:

#define А \x80 // А - русская
 
кстати, кроме проблемы с русскими буквами, тут есть другая - правила макроподстановки написаны так, что заменяют только отдельные идентификаторы, не затрагивая те случаи, когда макрос является частью другого слова.
 
То есть, если бы даже ТС сумел заставить пропроцессор зарегистрировать макрос из русской буквы "А" - в слове "МАМА" эта подстановка все равно бы не сработала
starcomputer
Offline
Зарегистрирован: 19.10.2021

b707 пишет:

То есть, если бы даже ТС сумел заставить пропроцессор зарегистрировать макрос из русской буквы "А" - в слове "МАМА" эта подстановка все равно бы не сработала

Вы имеете в виду, что нельзя было бы написать слово ?

Можно, я пробовал.

Serial.print("\x30\x31 - \x32\x33");

Выводит 01 - 23

starcomputer
Offline
Зарегистрирован: 19.10.2021

Rumata пишет:

Правда это решается проще - выбором правильной кодировки в ИДЕ

А как это сделать ?

 

starcomputer
Offline
Зарегистрирован: 19.10.2021

b707 пишет:

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

 
То есть, если бы даже ТС сумел заставить пропроцессор зарегистрировать макрос из русской буквы "А" - в слове "МАМА" эта подстановка все равно бы не сработала

Вы правы. Макрос не работает, если подстановка это часть чего-то :(

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Вы правы. Макрос не работает, если подстановка это часть чего-то :(

если подумать, это не ":(", а вовсе даже ":)"

Иначе задали бы вы макрос

#define R 256

а он бы вам в digitalRead() букву поменял :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Такое было возможно в старых версиях GCC. Потом исчезло из-за ошибки. Ошибка исправлена в GCC версии 10

Так что либо ждите пока разработчики IDE поставят 10-ку, либо ставьте её сами.

Кстати, присоединяюсь к вопросу из #2

starcomputer
Offline
Зарегистрирован: 19.10.2021

Изменение кодировки IDE даст нам возможность выводить русский текст в Serial, но не на LCD :(

 

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Такое было возможно в старых версиях GCC

вы имеете в виду "русские" символы?

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Изменение кодировки IDE даст нам возможность выводить русский текст в Serial, но не на LCD :(

почему? Какая разница?

starcomputer
Offline
Зарегистрирован: 19.10.2021

b707 пишет:

а он бы вам в digitalRead() букву поменял :)

Ну я собирался менять только русские буквы, о они в С++ не используются :)

starcomputer
Offline
Зарегистрирован: 19.10.2021

b707 пишет:

starcomputer пишет:

Изменение кодировки IDE даст нам возможность выводить русский текст в Serial, но не на LCD :(

почему? Какая разница?

Потому что LCD пофиг, какая там кодировка у IDE. Он выводит символы из своих шрифтов.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

ЕвгенийП пишет:

Такое было возможно в старых версиях GCC

вы имеете в виду "русские" символы?

Не только русские. Использование UTF-8 в идентификаторах.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

starcomputer пишет:

Потому что LCD пофиг, какая там кодировка у IDE. Он выводит символы из своих шрифтов.

У LCD нет никаких шрифтов. Он выводит то, что Вы ему подсунете программно.

starcomputer
Offline
Зарегистрирован: 19.10.2021

ЕвгенийП пишет:

b707 пишет:

ЕвгенийП пишет:

Такое было возможно в старых версиях GCC

вы имеете в виду "русские" символы?

Не только русские. Использование UTF-8 в идентификаторах.

Ну поскольку идентификатор должен быть целым, а не частью строки, то это не актуально :(

 

starcomputer
Offline
Зарегистрирован: 19.10.2021

ЕвгенийП пишет:

starcomputer пишет:

Потому что LCD пофиг, какая там кодировка у IDE. Он выводит символы из своих шрифтов.

У LCD нет никаких шрифтов. Он выводит то, что Вы ему подсунете программно.

Я имел ввиду те шрифты, которые мы ему подсовываем программно :)

extern uint8_t BigFont[];

 

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Потому что LCD пофиг, какая там кодировка у IDE. Он выводит символы из своих шрифтов.

напишите свою функцию recode(). которая будет принимать слово "МАМА" в UTF. а на выходе выдавать строчку из шестнадцатиричных кодов.

И потом вызывайте вот так:

LCD.print(recode("MAMA"));

 

starcomputer
Offline
Зарегистрирован: 19.10.2021

Не, лучше я библиотеку UTFT перепишу. Собственно ДОперепишу, ибо она уже и так сильно переписана.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

напишите свою функцию recode(). 

Вот, не любите Вы ООП :-(

starcomputer
Offline
Зарегистрирован: 19.10.2021

Да, ООП это сила, но и ресурсы жрет хорошо :(

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

starcomputer пишет:

ресурсы жрет хорошо :(

Чойта?

rkit
Offline
Зарегистрирован: 23.11.2016

starcomputer пишет:

Да, ООП это сила, но и ресурсы жрет хорошо :(

Ну приехали теперь.

starcomputer
Offline
Зарегистрирован: 19.10.2021

Потому что когда пишешь свой класс, то стараешься его сделать универсальным, "на все случаи жизни".

В результате в классе куча case, if ... else и т.п., которые в 70% случаев не используются.

Изначальный файл UTFT.cpp весит 27,8 кб

Урезанная (и несколько расширенная) библиотека с теми же (и еще ++) функциями но для ОДНОГО определенного контроллера (SSD1963) и ОДНОГО экрана весит 19,5 кб. И можно еще почистить.

starcomputer
Offline
Зарегистрирован: 19.10.2021

Написание классов более удобно для программиста, чем дает какой-либо эффект (при условии, что у Вас создается ОДИН объект класса).

В частности дисплей в 99% случаев один :)

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Потому что когда пишешь свой класс, то стараешься его сделать универсальным, "на все случаи жизни".

В результате в классе куча case, if ... else и т.п., которые в 70% случаев не используются.

поэтому надо писать не через if case, а через условную компиляцию и шаблоны

Цитата:
Изначальный файл UTFT.cpp весит 27,8 кб

Урезанная (и несколько расширенная) библиотека с теми же (и еще ++) функциями но для ОДНОГО определенного контроллера (SSD1963) и ОДНОГО экрана весит 19,5 кб. И можно еще почистить.

с каких это пор размер ИСХОДНИКА стал указывать на размер обьектного кода? Вы в курсе про оптимизацию? Компилятор сам выкинет неиспользуемые функции

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

starcomputer пишет:

Потому что когда пишешь свой класс, то стараешься его сделать универсальным, "на все случаи жизни".

В результате в классе куча case, if ... else и т.п., которые в 70% случаев не используются.

Если руки из %опы, не нужно винить ООП. Если даже компилятор (а он очень умный) не может сделать твой код компактным, стоит задуматься о вечном..

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

starcomputer пишет:

Да, ООП это сила, но и ресурсы жрет хорошо :(

Если готовить не умеешь, то даже рис сварить сложно. Либо деревянный будет, либо размазня. Вот и с ООП тоже самое. Чаще всего размер кода вообще никак не изменяется, а еще чаще - оптимизатор сделает лучше человека-погромиста. ;))

Есть в позднем ООП всякие инструменты, порождающие большой код, но это не касается МК.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

b707 пишет:

Компилятор сам выкинет неиспользуемые функции

Дааа..

starcomputer
Offline
Зарегистрирован: 19.10.2021

Ну и как компилятор отсюда:

UTFT::UTFT(byte model, int RS, int WR, int CS, int RST, int SER)
{ 
	word	dsx[] = {239, 239, 239, 239, 239, 239, 175, 175, 239, 127,						// 00-09
					 127, 239, 271, 479, 239, 239, 239, 239, 239, 239,						// 10-19
					 479, 319, 239, 175,   0, 239, 239, 319, 319, 799,						// 20-29
					 127};																	// 30-
	word	dsy[] = {319, 399, 319, 319, 319, 319, 219, 219, 399, 159,						// 00-09
					 127, 319, 479, 799, 319, 319, 319, 319, 319, 319,						// 10-19
					 799, 479, 319, 219,   0, 319, 319, 479, 479, 479,						// 20-29
					 159};																	// 30-
	byte	dtm[] = {16, 16, 16, 8, 8, 16, 8, SERIAL_4PIN, 16, SERIAL_5PIN,					// 00-09
					 SERIAL_5PIN, 16, 16, 16, 8, 16, LATCHED_16, 16, 8, 8,					// 10-19
					 16, 16, 16, 8, 0, SERIAL_5PIN, SERIAL_4PIN, 16, 16, 16,				// 20-29
					 SERIAL_5PIN};															// 30-

	disp_x_size =			dsx[model];
	disp_y_size =			dsy[model];
	display_transfer_mode =	dtm[model];
	display_model =			model;

	__p1 = RS;
	__p2 = WR;
	__p3 = CS;
	__p4 = RST;
	__p5 = SER;

	if (display_transfer_mode == SERIAL_4PIN)
	{
		display_transfer_mode=1;
		display_serial_mode=SERIAL_4PIN;
	}
	if (display_transfer_mode == SERIAL_5PIN)
	{
		display_transfer_mode=1;
		display_serial_mode=SERIAL_5PIN;
	}

	if (display_transfer_mode!=1)
	{
		_set_direction_registers(display_transfer_mode);
		P_RS	= portOutputRegister(digitalPinToPort(RS));
		B_RS	= digitalPinToBitMask(RS);
		P_WR	= portOutputRegister(digitalPinToPort(WR));
		B_WR	= digitalPinToBitMask(WR);
		P_CS	= portOutputRegister(digitalPinToPort(CS));
		B_CS	= digitalPinToBitMask(CS);
		P_RST	= portOutputRegister(digitalPinToPort(RST));
		B_RST	= digitalPinToBitMask(RST);
		if (display_transfer_mode==LATCHED_16)
		{
			P_ALE	= portOutputRegister(digitalPinToPort(SER));
			B_ALE	= digitalPinToBitMask(SER);
			cbi(P_ALE, B_ALE);
			pinMode(8,OUTPUT);
			digitalWrite(8, LOW);
		}
	}
	else
	{
		P_SDA	= portOutputRegister(digitalPinToPort(RS));
		B_SDA	= digitalPinToBitMask(RS);
		P_SCL	= portOutputRegister(digitalPinToPort(WR));
		B_SCL	= digitalPinToBitMask(WR);
		P_CS	= portOutputRegister(digitalPinToPort(CS));
		B_CS	= digitalPinToBitMask(CS);
		if (RST != NOTINUSE)
		{
			P_RST	= portOutputRegister(digitalPinToPort(RST));
			B_RST	= digitalPinToBitMask(RST);
		}
		if (display_serial_mode!=SERIAL_4PIN)
		{
			P_RS	= portOutputRegister(digitalPinToPort(SER));
			B_RS	= digitalPinToBitMask(SER);
		}
	}
}

что-то выкинет ? :)

А у меня ОДНА модель дисплея. Мне не нужны массивы dtx,dty,dtm. Мне не нужны переменные display_transfer_mode и display_model и связанные с ними if...else. Мне не нужны остальные if...else в зависимости от ориентации дисплея.

Если все это убрать, то:

UTFT::UTFT(byte model, int RS, int WR, int CS, int RST, int SER)
{ 
	disp_x_size = 479;
	disp_y_size = 799;

	__p1 = RS;
	__p2 = WR;
	__p3 = CS;
	__p4 = RST;
	__p5 = SER;

	_set_direction_registers(16);
	P_RS	= portOutputRegister(digitalPinToPort(RS));
	B_RS	= digitalPinToBitMask(RS);
	P_WR	= portOutputRegister(digitalPinToPort(WR));
	B_WR	= digitalPinToBitMask(WR);
	P_CS	= portOutputRegister(digitalPinToPort(CS));
	B_CS	= digitalPinToBitMask(CS);
	P_RST	= portOutputRegister(digitalPinToPort(RST));
	B_RST	= digitalPinToBitMask(RST);
}

Если все это писать на директивах препроцессора, то там сам черт голову сломает :)

 

starcomputer
Offline
Зарегистрирован: 19.10.2021

Я не против ООП, всю жизнь пишу на Delphi.

Но оно не всегда благо :)

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Что из этого относится к ООП?

И Delphi - не язык программирования. 

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Если все это убрать, то:

это вы идете по гнилому пути Гайвера. Он тоже очень любит системные библиотеки переписывать, создавая "мини_" версии, выкидывая оттуда то, что по его мнению, лишнее. А потом юзеры не могут понять, почему у одного библиотека работает, а у другого, казалось бы в том же скетче - нет.

starcomputer
Offline
Зарегистрирован: 19.10.2021

Юзер, если хочет, может использовать и системную библиотеку, но она будет медленнее работать.

Я пишу для своих проектов и к тому-же всегда можно четко указать, для какого дисплея с каким контроллером эта библиотека :)

Кстати юзеры чаще ищут библиотеку, которая будет четко работать с конкретно ИХ дисплеем, а то, что она поддерживает еще два десятка других их мало волнует. А потом вопросы "А почему в библиотеке есть функция регулировки яркости, а у меня она не работает ?"

Да потому что она работает только на НЕКОТОРЫХ контроллерах, а библиотека для ВСЕХ.

starcomputer
Offline
Зарегистрирован: 19.10.2021

Класс UTFT разве не ООП ?

Ну хорошо, на Объектно-Ориентированном Паскале :)

 

starcomputer
Offline
Зарегистрирован: 19.10.2021

Rumata пишет:

Что из этого относится к ООП?

И Delphi - не язык программирования. 

Ответил выше :)

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

starcomputer пишет:

 

Ответил выше :)

Отлично! Напишите аналогичный функционал для всего зоопарка устройств на процедурном С без использования ООП и приведите для сравнения размер скомпилированного кода. Заранее спасибо

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Или еще проще, напиши маленький класс "hello world" и сравни с обычным Serial.println("Hello world")

starcomputer
Offline
Зарегистрирован: 19.10.2021

А зачем мне это ? :) И это вообще не нужно. Вот сейчас я буду переписывать библиотеку soft_uart, потому что там SoftSerial создается не как класс, а мне нужен именно объект SoftSerial для дальнейшего использования.

Если Вы перепишите ту-же UTFT, в отдельности для разных контроллеров и дисплеев в разном сочетании, то суммарный размер кода будет в тысячу раз больше. Речь не о том.

Или Вы считаете, что иметь в программе не нужный код это высший класс программирования ?

void UTFT::lcdOff()
{
	cbi(P_CS, B_CS);
	switch (display_model)
	{
	case PCF8833:
		LCD_Write_COM(0x28);
		break;
	case CPLD:
		LCD_Write_COM_DATA(0x01,0x0000);
		LCD_Write_COM(0x0F);   
		break;
	}
	sbi(P_CS, B_CS);
}

Эта функция вызывается, значит компилятор ее включит в общий код, только вот в ней НЕТ моего контроллера.

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

Такое было возможно в старых версиях GCC. Потом исчезло из-за ошибки. Ошибка исправлена в GCC версии 10

Так что либо ждите пока разработчики IDE поставят 10-ку, либо ставьте её сами.


Наблюдал подобное в дружественном семействе.) Типа:
#define FCPU 8MHZ
#define MHZ  *1000000

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

void UTFT::lcdOff()
{
	cbi(P_CS, B_CS);
	switch (display_model)
	{
	case PCF8833:
		LCD_Write_COM(0x28);
		break;
	case CPLD:
		LCD_Write_COM_DATA(0x01,0x0000);
		LCD_Write_COM(0x0F);   
		break;
	}
	sbi(P_CS, B_CS);
}

Эта функция вызывается, значит компилятор ее включит в общий код, только вот в ней НЕТ моего контроллера.

это снова к вопросу о правильном программировании. Если display_model описана как константа и не равна ни одному из вариантов case - оптимизатор выкинет из кода все между двумя операторами sbi

о пользе использования const

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

starcomputer пишет:

ресурсы жрет хорошо :(

Это если готовить не уметь.

starcomputer пишет:

Изначальный файл UTFT.cpp весит 27,8 кб

Урезанная (и несколько расширенная) библиотека с теми же (и еще ++) функциями но для ОДНОГО определенного контроллера (SSD1963) и ОДНОГО экрана весит 19,5 кб. И можно еще почистить.

Вот-вот, тот самый случай.

starcomputer пишет:

Класс UTFT разве не ООП ?

Нет!

Само по себе пихание слова class куда ни попадя - ни грамма не ООП.  ООП - это архитектура программы, а не язык и не ключевые слова. В парадигме ООП можно писать и там, где никаких классов отродясь не было (хоть на ассемблере). 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

starcomputer пишет:

Я к тому, что процедурное программирование не имеет при прочих равных преимущества перед ООП по размеру кода. В большинстве случаев существенно проигрывает.

starcomputer
Offline
Зарегистрирован: 19.10.2021

ЕвгенийП пишет:

Нет!

Само по себе пихание слова class куда ни попадя - ни грамма не ООП.  ООП - это архитектура программы, а не язык и не ключевые слова. В парадигме ООП можно писать и там, где никаких классов отродясь не было (хоть на ассемблере). 

Расшифруйте мне словосочетание ООП :)

И как можно писать на ООП если нет объектов ?

Вы можете создать объект без класса ? Приведите пример.

starcomputer
Offline
Зарегистрирован: 19.10.2021

b707 пишет:

это снова к вопросу о правильном программировании. Если display_model описана как константа и не равна ни одному из вариантов case - оптимизатор выкинет из кода все между двумя операторами sbi

о пользе использования const

Да, но она то описана как переменная.

Те-же пины дисплея, они что меняются во время работы программы ? Зачем их делать переменными ?

#define RS ..

#define WR ..

и никаких переменных.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

starcomputer пишет:

#define RS ..

#define WR ..

и никаких переменных.

за #define в библиотеках лично я бы руки отрубал. Жалко тебе 1-4 байта на переменную? Нет, пусть потом пользователи при отладке потрахаются

b707
Offline
Зарегистрирован: 26.05.2017

starcomputer пишет:

Те-же пины дисплея, они что меняются во время работы программы ? Зачем их делать переменными ?

вот именно, они должны быть константами, с классификатором const

использование #define давно уже не рекомендовано в стандарте, у дефайнов очень много минусов

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

starcomputer пишет:

Расшифруйте мне словосочетание ООП :)

В словарь загляните.

starcomputer пишет:

И как можно писать на ООП если нет объектов ?

Никак. 

starcomputer пишет:

Вы можете создать объект без класса ? 

Кончено, могу.

starcomputer пишет:

Приведите пример.

Возьмите любую сколько-нибудь нетривиальную программу на первых версиях ECMAScript. Классов нет в природе, а объектов и наследуемых (в т.ч. и множественно), и полиморфных, и каких угодно ...

Почитайте вот это. Я там со многим не согласен и поспорил бы, но суть подхода - это как раз то, что я пытаюсь Вам  сказать.