Вопрос к небожителям от сирых и убогих.

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

Green пишет:

Про Эру расскажите. Интересно.

Обязательно, здесь же в отвлечённых в ближайшие день-два

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Про Эру расскажите. Интересно.

конечно интересно, что еще кроме строевой )))

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

раскомментить любую из строк 17 или 19 в .ino, в setup()

IDE 1.8.9

Ну и, по традиции, "ПАМАГИТИ!!!!"

Подтверждаю проблему на 1.8.8.

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

 

Лучше бы озаботился тем, что из-за бездумног IndexOf у тя стало 2 прохода по массиву. Искал бы по ходу в том цикле где печать так и одним обошелся.

ПС. Неделю назад втыкал. Так работает


  switch(statusCool)
  {
....
  case 3:  //первое достоверное значение датчика 0 (внутри)
     TermObj = Termo1Val;

  myOLED.drawString(0,3,"term2 ");
  statusCool++;
    return;

  case 4:   
     TermAir = Termo1Val;
    statusCool++;
     break;

И так работает



  switch(statusCool)
  {
....
  case 3:  //первое достоверное значение датчика 0 (внутри)
     TermObj = Termo1Val;
     itoa(Termo1Val, s, 10);
     uint8_t n=strlen(s);
     s[n]=s[n-1];
     s[n-1]=',';
     s[n+1]=0;
  myOLED.drawString(0,1,s);
  myOLED.drawString(0,3,"term2 ");
  statusCool++;
    return;

  case 4:   
     TermAir = Termo1Val;

     statusCool++;
     break;

А так в case 4 и все следующие не заходит. Хотя statusCool равен 4, зуб даю! я его и на экран и в сириал!

8))

  switch(statusCool)
  {
....
  case 3:  //первое достоверное значение датчика 0 (внутри)
     TermObj = Termo1Val;
     itoa(Termo1Val, s, 10);
     uint8_t n=strlen(s);
     s[n]=s[n-1];
     s[n-1]=',';
     s[n+1]=0;
  myOLED.drawString(0,1,s);
  myOLED.drawString(0,3,"term2 ");
  statusCool++;
    return;

  case 4:   
     TermAir = Termo1Val;
     itoa(Termo1Val, s, 10);
     n=strlen(s);
     s[n]=s[n-1];
     s[n-1]=',';
     s[n+1]=0;
  myOLED.drawString(6,1,s);
     statusCool++;
     break;

А вот так снова работает

uint8_t n;

  switch(statusCool)
  {
....
  case 3:  //первое достоверное значение датчика 0 (внутри)
     TermObj = Termo1Val;
     itoa(Termo1Val, s, 10);
     n=strlen(s);
     s[n]=s[n-1];
     s[n-1]=',';
     s[n+1]=0;
  myOLED.drawString(0,1,s);
  myOLED.drawString(0,3,"term2 ");
  statusCool++;
    return;

  case 4:   
     TermAir = Termo1Val;
     itoa(Termo1Val, s, 10);
     n=strlen(s);
     s[n]=s[n-1];
     s[n-1]=',';
     s[n+1]=0;
  myOLED.drawString(6,1,s);
     statusCool++;
     break;

Оно конечно обявить переменную снаружи от свича наверно красивше будет чем в одном из кейсов как вышло в следствие копипаста. Ну так ладно бы не собиралось и ткнуло носом что здесь фигня. Так нет же, сука полупроводниковая, измывается над человеком!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

и ворнингов нету?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вопщем, нада на Паскаль переходить.  Там 20-ти томов стандартов хоть и нету, но я в класс всё что угодно могу инкапсулировать.  А тут придется прятать на уровне модулей (единиц компиляции).  Дурдом, каоче, нада напица.  Пойду я. 

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

и ворнингов нету?

Нету нихрена. Токо шо включил спецом "Все". Даже так нету.

ПС. Но польза есть, странный

SSD1306.cpp:156:5: warning: 'r' may be used uninitialized in this function [-Wmaybe-uninitialized]     for (;r;r--) 

в моей же либе оказывается!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Вопщем, нада на Паскаль переходить.  Там 20-ти томов стандартов хоть и нету, но я в класс всё что угодно могу инкапсулировать.  А тут придется прятать на уровне модулей (единиц компиляции).  Дурдом, каоче, нада напица.  Пойду я. 

кто не может паскалить тот будет сикать?

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

 А тут придется прятать на уровне модулей (единиц компиляции). 

так и нормально.  А вобще от кого прячем? ;) И шо удастся? А если найду ;)

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

Дед! Пока Женя думает вот самый короткий пример:

теперь комментарии:

1. как видишь я добавил gnu++17.

2. полученный через констэкспр такой элемент класса, как видишь не становится настоящим. То есть компилятор пропускает, а линковщик  дает ошибку. Это уже не АВР, это просто Линух и VSCode с GCC.

3. Все еще надеюсь на то, что Женя знает о стандарте больше меня, а так оно и есть, и найдет способ инициализации не интегральных статиков.

==================

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

причем в dadaLen нужно писать именно имя _someData - внешнего массива, а не someData. Иначе констэкпр считает неправильно.

Logik
Offline
Зарегистрирован: 05.08.2014

Этот пример на принт из стр19. А самое загадочное - принт стр17.

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

Logik пишет:

Этот пример на принт из стр19. А самое загадочное - принт стр17.

без этой строки компилятор  создает код иначе. Пользуется данными этапа компиляции, в котором он нормально обработал все выражения и статики Дедова класса. А с ней - уже передает линковщику ссылки... которых в реале нет ;))))

---------

И да - это конечно глюк. Вот прям маслице для любителей поругать компилятор!  ;))) Логик может плясать. У кого-то есть компилятор лучше?

Logik
Offline
Зарегистрирован: 05.08.2014

Я уже вызвал циган с медведями на балалайках!

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

Тезис что софта без глюков не бывает теперь можно считать истинным?

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

wdrakula пишет:

вот самый короткий пример:

Да, пример, то у меня короче есть

struct classArray_t {
	static constexpr unsigned char Array[] = { 'O', 'k' };
};

int main(void) {
	putchar(classArray_t::Array[rand()]);
}

Результат: в ардуине и в AVR-студии одинаковая ошибка, а в мелкомягком компиляторе и в билдере - всё компилируется на ура.

Вопрос-то всё равно остаётся - что провоцирует такое поведение? Я в этом пытаюсь разобраться. Понятно же, что деду не нужен совет "как сделать, чтобы работало" - это он и без нас отлично сделает. Ему любопытно "чё за хрень". Мне тоже.

То, что программист тут "выпендрился" в общем-то понятно, но компилятор должен был разобраться и либо оставить массив в памяти (наплевав на constexpr), либо развернуть цикл и уйти от переменной в индексе. Но он, похоже, черезчур увлёкся оптимизацией. Ладно, следствие продолжается.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

так, посоветуйте теперь дизассемблер, посмотреть, что там накомпилировалось

Logik
Offline
Зарегистрирован: 05.08.2014

а шож им дизасемблить если ниче не собралось. Почти уверен что мелкомягкий компилятор просто забил на оптимизацию, вот оно и прошло :) Иногда лучший подход к проблеме - забить хер. В данном случае забили оптимизировать.

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

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

Да, пример, то у меня короче есть

struct classArray_t {
	static constexpr unsigned char Array[] = { 'O', 'k' };
};

int main(void) {
	putchar(classArray_t::Array[rand()]);
}

Результат: в ардуине и в AVR-студии одинаковая ошибка, а в мелкомягком компиляторе и в билдере - всё компилируется на ура.

Женя! Это глюк GCC, свой пример я компилировал просто на компе. Линух Минт 64 бита.

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

ну да. Вот пример Жени на GCC 5.4.0.


#include <iostream>
using namespace std;

struct classArray_t {
	static constexpr unsigned char Array[] = { 'O', 'k' };
};

int main(void) {
	cout << classArray_t::Array[rand()];
}
============================

> Executing task: /usr/bin/g++ -std=gnu++17 -g /home/wlad/SOFT/cpp/test3.cpp -o /home/wlad/SOFT/cpp/test3 <

/tmp/ccabBN16.o: In function `main':
/home/wlad/SOFT/cpp/test3.cpp:10: undefined reference to `classArray_t::Array'
collect2: error: ld returned 1 exit status
The terminal process terminated with exit code: 1

Опять ошибка от линковщика.

вот обход. Мне всегда только это интересно. Ошибки в софте, даже таком проверенном миллионами, как GCC - нормально.

#include <iostream>
#include <stdlib.h>
using namespace std;

unsigned char _Array[] = { 'O', 'k' };
struct classArray_t {
	static constexpr unsigned char* Array = _Array;
};

int main(void) {
    cout << classArray_t::Array[1&rand()] << endl;
}

===============

Я не нашел, где бы в стандарте было РАЗРЕШЕНО инициализировать статик элементы неинтегрального (хотя по русски надо говорить "несчетного") типа. Если некоторые компиляторы это пропускают - здорово.

Плохо, что GCC на этапе компиляции не ругается, но и не создает массив в памяти. Это глюк. Надо о нём знать.

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

вот обход. Мне всегда только это интересно. Ошибки в софте, даже таком проверенном миллионами, как GCC - нормально.

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

Вопрос-то всё равно остаётся - что провоцирует такое поведение? Я в этом пытаюсь разобраться. Понятно же, что деду не нужен совет "как сделать, чтобы работало" - это он и без нас отлично сделает. Ему любопытно "чё за хрень". Мне тоже.

Да. Я понять хочу, с тем ли канпилятором я связался. :-) итииемать. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Пошто я в Дельфи могу инкапсулировать в класс все, что угодно, а в этомязыке могу, канеш, тока как то черезжопу и не всегда. :-) 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вопщем, нада, хлебнув кваску, писать свой канпилятор, с преферансом и библиотекаршами. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

И этта. До понедельника мы с котом - ватключке. :-)

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

DetSimen пишет:

Да. Я понять хочу, с тем ли канпилятором я связался. :-) итииемать. 

Не, ну, ты сам то пиши правильно! Твой вопрос же не о прямой ошибке компилятора, а о неправильной реакции на ошибку программиста, разве не так? Если бы ты написал правильно, то и проблем бы не было. А так, ты, конечно прав, он должен был либо ругнуться, либо послать твой constexpr и разместить массив в памяти (может ещё предупреждение выдать). А он, сволочь, пропустил молча и подсунул свинью линкеру.

В стандарте прямо сказано (разд 12.2.3.2(3) на стр. 249): "If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. The member shall still be defined in a namespace scope if it is odr-used in the program and the namespace scope definition shall not contain an initializer".

Большинство компиляторов позволяют этого не делать (не размещать определение), GCC тоже позволяет, но, как показала практика, не всегда корректно.

Т.е. если мы напишем точно по стандарту (твой .h файл)

#pragma once

static const char str1[] PROGMEM = "String1";
static const char str2[] PROGMEM = "String2";
static const char str3[] PROGMEM = "String3";

static const int8_t WRONG_INDEX = -1;

#pragma pack(push, 1)
struct structArray_t {
public: 
	const char *const Text;
	uint16_t	Code;
};
#pragma pack(pop)

class classArray_t {
public:
	static constexpr structArray_t Array[] = {
		{str1, 0xDEAD},
		{str2, 0xBEEF},
		{str3, 0xF00D}
	};

	static constexpr uint8_t ArraySize = sizeof(Array) / sizeof(Array[0]);

	static int8_t IndexOf(const uint16_t ACode) {
		for (int8_t i = 0; i < ArraySize; i++) {
			if (Array[i].Code == ACode) return i;
		}
		return WRONG_INDEX;
	}
};

constexpr structArray_t classArray_t::Array[]; // !!! НЕ НАДО ЗАБЫВАТЬ !!! 

то GCC глючить не будет -  я запускал со всеми раскомментированными строками - всё нормально пашет. А вот его реакция на нашу ошибку глюкавая. 

Важное замечание: разумеется добавленное мною определение нужно не в .h файле размещать, а то плодиться начнёт.

Блин, целый день траха чтобы понять, что GCC, видя constexpr  изо всех сил пытается не размещать его в памяти, а когда не получается, (А) не проверяет есть ли уже размещение и (Б) не размещает сам.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Спасибо ЕвгенийП за подробное объяснение, свою ошибку я понял. С++ дает инициализировать в описании только простенькие, "импотентские" типы.  Другие инициализаторы надо пхать в cpp файл.  Акей. 

Стандарты не читал, но осуждаю, как Пастернака. :) 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Опщем, можно тему удалять. :-)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Опщем, можно тему удалять. :-)

пока я не въеду о чём вы тут наговорили на 75 постов низзя