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

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Гасспада программисты, я уже ничо не понимаю, моя компетенция кончилась, растолкуйте. 

есть вот такой файл Header.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;
	}
};

и есть обычный Ордуиновский праэкт, полный текст: 

#include <Arduino.h>
#include "Header.h"


void setup() {
	Serial.begin(115200);

	Serial.println(F("Program started...."));

	Serial.print(" Array Size = ");
	Serial.println(classArray_t::ArraySize);

	for (uint8_t i = 0; i < classArray_t::ArraySize; i++) {

		Serial.print((__FlashStringHelper *)(classArray_t::Array[i].Text));

//		Serial.print("   Code = 0x");

//		Serial.print(classArray_t::Array[i].Code, HEX);

		Serial.println();
	}

	Serial.print("Index of Code 0xBEEF = ");
	Serial.println(classArray_t::IndexOf(0xBEEF));

	uint16_t Code = classArray_t::Array[2].Code;

	Serial.print("Array.Code[2] = 0x");
	Serial.println(Code, HEX);
}

void loop() {
  
}

В таком виде, как я привел, все работает, вывод в Сериал есть

 

как тока я раскомментироваю любую из строк,  всё, не компилируеца, со странными ошибками

Я вапще не понимаю в чём дело.  

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

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

IDE 1.8.9

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

svm
Offline
Зарегистрирован: 06.11.2016

У меня тоже наблюдаются странности с сериалом. Причем на разных компах разные. На всех стоит одна и та-же IDE 1.6.9  Чаще всего после отладки программы и удаления инициализации сериала или одной из строк вывода в сериал программа перестает компилится. Иногда помогает перенос папки проекта в корень диска. Иногда компиляция в IDE 1.6.5   После чего все компилится и в 1.6.9   Никакой связи между IDE нет (стоят на разных дисках)  Системы никакой не обнаружил.  По идее 17 строка - самая безобидная. Но в Вашей ситуации эти фокусы не проходят. Но если закоментировать 21 строку, то можно раскоментировать 19, а 15 разрешает println применить. Мистика.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

А у тебя канпилируеца? 

svm
Offline
Зарегистрирован: 06.11.2016

Нет, но я выше добавил как компилируется. В общем чудеса. Но ошибки от твоих отличаются. Если поможет могу лог скинуть.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

svm пишет:

 Мистика.

Согласен 146%  :)

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

svm пишет:

Нет, но я выше добавил как компилируется. В общем чудеса. Но ошибки от твоих отличаются. Если поможет могу лог скинуть.

Думаю, взрослые заглянут, объяснят нам. 

svm
Offline
Зарегистрирован: 06.11.2016
Arduino: 1.6.9 (Windows XP), Плата:"Arduino Pro or Pro Mini, ATmega328 (5V, 16 MHz)"
 
C:\DOCUME~1\SVM~1\LOCALS~1\Temp\cc4GlpDg.ltrans0.ltrans.o: In function `main':
 
cc4GlpDg.ltrans0.o:(.text.startup+0x126): undefined reference to `classArray_t::Array'
 
cc4GlpDg.ltrans0.o:(.text.startup+0x128): undefined reference to `classArray_t::Array'
 
cc4GlpDg.ltrans0.o:(.text.startup+0x152): undefined reference to `classArray_t::Array'
 
cc4GlpDg.ltrans0.o:(.text.startup+0x154): undefined reference to `classArray_t::Array'
 
collect2.exe: error: ld returned 1 exit status
 
exit status 1
Ошибка компиляции для платы Arduino Pro or Pro Mini.
 
Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"
 
Это с раскомментированными строками
DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ну у мня тоже undefined reference.  Толи линкер тупой, то ли я банбанутый. 

Наерна, куплю коньяк, свечи, да в полночь перед зеркалами будем с котом вызывать ЕвгенийП из Анапы.  :) 

svm
Offline
Зарегистрирован: 06.11.2016

DetSimen пишет:

ну у мня тоже undefined reference.  Толи линкер тупой, то ли я банбанутый. 

Наерна, куплю коньяк, свечи, да в полночь перед зеркалами будем с котом вызывать ЕвгенийП из Анапы.  :) 

Для надежности купи себе бубен, а коту бубенчики. Если не помогут, то хотя-бы родные поржут :)

astwo
Offline
Зарегистрирован: 10.07.2019

Зачем коту бубенчики. Он что родных лишился из-за плохого поведения.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

бубен у меня есть со времен админства.   

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

astwo пишет:
Он что родных лишился из-за плохого поведения.

Лишился.  12 лет назад

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

DetSimen пишет:

ну у мня тоже undefined reference.  Толи линкер тупой, то ли я банбанутый. 

Наерна, куплю коньяк, свечи, да в полночь перед зеркалами будем с котом вызывать ЕвгенийП из Анапы.  :) 

Он случаем не в Эра???

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

ded , я не дома щас, но проведи икскримент: хедер включи в текст напрямую, не инклюдом.

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

всё я с телефона нашёл твоё решение. Прости текст голосом набираю. нужно использовать атрибут used. погугли про него мне трудно с телефона набирать.

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

это lto сокращает твой код.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

О, вот и взрослые подтянулись.  

Включил. 

#include <Arduino.h>
//#include "Header.h"


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;
	}
};


void setup() {
	Serial.begin(115200);

	Serial.println(F("Program started...."));

	Serial.print(" Array Size = ");
	Serial.println(classArray_t::ArraySize);

	for (uint8_t i = 0; i < classArray_t::ArraySize; i++) {

		Serial.print((__FlashStringHelper *)(classArray_t::Array[i].Text));

//		Serial.print("   Code = 0x");

//		Serial.print(classArray_t::Array[i].Code, HEX);

		Serial.println();
	}

	Serial.print("Index of Code 0xBEEF = ");
	Serial.println(classArray_t::IndexOf(0xBEEF));

	uint16_t Code = classArray_t::Array[2].Code;

	Serial.print("Array.Code[2] = 0x");
	Serial.println(Code, HEX);
}

void loop() {
  
}

с комментариями в setup()  всё канпилируеца и даже работает как надо.  Снимаешь комментарий с любой строки - амба. Инжалид референце. 

Хотя строки ниже цикла делают то же самое, что и в цикле.  :)  

никада я в этот лжывый язык не въехаю. 

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

__attribute__((used)) нужно написать у переменной твоего хитрожопого класса! ;))))

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

Линк тайм оптимизейшн ( lto)он тупой. нет переменной класса выкинет все методы и пр. даже Статик. либо прагмой лто отключай, либо юзед попробуй.
Я сейчас не могу полный help по gcc прочесть. жду жену в машине у салона красоты, это святое!!!

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

DetSimen пишет:

Хотя строки ниже цикла делают то же самое, что и в цикле.  :)


нет, не тоже! они в компайлтайм считаются.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

А пошто этот LTO хитровыделанный вот это не выкинул, а спокойно так пропустил, и оно даже правильно работает в цыкале: 

        Serial.print((__FlashStringHelper *)(classArray_t::Array[i].Text));

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

класс, с.ка, чисто статический, и методы у него, аж целый один, тоже статический и остальные члены тоже.  

почему вне цикла я могу вызвать статический метод, а унутре все перебрать - хрен мне в сумку?  

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

wdrakula пишет:
__attribute__((used)) нужно написать у переменной твоего хитрожопого класса! ;))))

нету у меня переменной этого класса, ни к чему она. 

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

ты зачем спорить? просто отключи лто и проверь. я же могу быть неправ. я проверить сейчас не могу.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

щас найду как и отключу всенепременнейшэ.  Мне такой LTO не нужен. :)

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Мда.  Даже не могу найти как LTO отключить чёртов. 

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

опция компилятора -lto

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Я уже в магазин побрёл,  головою свесясь, за фафнуриком. Теперь уже завтра проверю

Komandir
Offline
Зарегистрирован: 18.08.2018

:-)

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

Дракула, lto тут не при чем, имхо. Обрати внимание, что ошибка возникает, если расскомментить ЛЮБУЮ из строк 50 или 52 в коде #17.

ТО есть даже ту, где никакой classArray_t::Array не упоминается :

Serial.print("   Code = 0x");

 

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

только что проверил - вот такой вот код отлично собирается

void setup() {
  Serial.begin(115200);

  Serial.println(F("Program started...."));

  Serial.print(" Array Size = ");
  Serial.println(classArray_t::ArraySize);

  for (uint8_t i = 0; i < classArray_t::ArraySize; i++) {

    Serial.print((__FlashStringHelper *)(classArray_t::Array[i].Text));
    uint16_t Code = classArray_t::Array[i].Code;
    //Serial.println("Hello!");
 }

а вот если раскомментировать последнюю печать - возникает ошибка. Причем печать-то вовсе с классом никак не связана

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Дак и я про то же. :-)

gfx125
Offline
Зарегистрирован: 27.05.2017

b707 пишет:

Дракула, lto тут не при чем, имхо. Обрати внимание, что ошибка возникает, если расскомментить ЛЮБУЮ из строк 50 или 52 в коде #17.

ТО есть даже ту, где никакой classArray_t::Array не упоминается :

Serial.print("   Code = 0x");

 

А у меня с раскоментированной строкой

Serial.print("   Code = 0x");

нормально компилится. Вот

 

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

А у тя какой IDE номер?

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

докладываю - в моем случае убирание опции -flto в четырех местах

compiler.c.flags=

compiler.c.elf.flags=

compiler.S.flags=

compiler.cpp.flags=

не помогло, ошибка компиляции та же. ИДЕ перезапускал. версия 1.6.12

Пусть Дракула придет и обьяснит все :)

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Мда. Ладно, добрые люди попишут-попишут, да выпьют бутылочку. Вот и моя очереть пришла. Вопщем, завтра уже разбираца буду.

gfx125
Offline
Зарегистрирован: 27.05.2017

DetSimen пишет:

А у тя какой IDE номер?

1.8.10

 

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

DetSimen пишет:

Мда.  Даже не могу найти как LTO отключить чёртов. 

ставь лодыря miniCore и будет тебе счастье )))

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

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

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

пойду тож напиццо! завтра может придумаю какой-то путь. Всякие простые типы можно инициализировать. инт, чар и пр. Надо как-то обмануть компилятор.

svm
Offline
Зарегистрирован: 06.11.2016

wdrakula пишет:

пойду тож напиццо! завтра может придумаю какой-то путь. Всякие простые типы можно инициализировать. инт, чар и пр. Надо как-то обмануть компилятор.

Не нарушайте традиции! Сегодня только Четверг. А вот завтра можно. И глядишь какая нибудь дурная идея выстрелит.

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

Вот так собирается!!!! ;))))))))

то есть все иниты статиков вынести за класс, в том же порядке.

А констэкспр - вражеское изобретение, честного человека путающее!!! ;)))))

----

ЗЫ: может метод и не обязательно выносить... тут мне уж лень дальше проверять... самогон греется, а курица стынет!

#include <Arduino.h>
//#include "Header.h"
#pragma GCC optimize "O0"

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 structArray_t Array[3] ;

    static uint8_t ArraySize;

    static int8_t IndexOf(const uint16_t);
};

structArray_t classArray_t::Array[3] = {
  { str1, 0xDEAD },
  { str2, 0xBEEF },
  { str3, 0xF00D }
};

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

uint8_t classArray_t::ArraySize = sizeof(Array) / sizeof(Array[0]);

//void setup() __attribute__((optimize("O0")));
void setup()  {




  Serial.begin(115200);

  Serial.println(F("Program started...."));

  Serial.print(" Array Size = ");
  Serial.println(classArray_t::ArraySize);

  for (uint8_t i = 0; i < classArray_t::ArraySize; i++) {

    Serial.print((__FlashStringHelper *)(classArray_t::Array[i].Text));

    Serial.print("   Code = 0x");

    Serial.print(classArray_t::Array[i].Code, HEX);

    Serial.println();
  }

  Serial.print("Index of Code 0xBEEF = ");
  Serial.println(classArray_t::IndexOf(0xBEEF));

  uint16_t Code = classArray_t::Array[2].Code;

  Serial.print("Array.Code[2] = 0x");
  Serial.println(Code, HEX);
}

void loop() {

}

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

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

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

wdrakula пишет:

Вот так собирается!!!! ;))))))))

А констэкспр - вражеское изобретение, честного человека путающее!!! ;)))))

ага, собирается, только вариант Деда с констэкспр занимал ровно в полтора раза меньше места - 1940 байт против 2740 тут :)

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

DetSimen пишет:

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

Может у Жени есть какой-то хитрый рецепт расширения компилятора, о котором я не знаю, и которое позволяет инициализировать статик в описании класса. Я писал, что это можно с с14 для простых типов, а вот для массива.... ХЗ. Самому интересно.

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

b707 пишет:

wdrakula пишет:

Вот так собирается!!!! ;))))))))

А констэкспр - вражеское изобретение, честного человека путающее!!! ;)))))

ага, собирается, только вариант Деда с констэкспр занимал ровно в полтора раза меньше места - 1940 байт против 2740 тут :)

сорян, забыл прагму, отключающую оптимизацию убрать.

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

ua6em пишет:

Он случаем не в Эра???

А где ещё?!? Но уже вернулся, вот только что домой зашёл.

Кстати, обратно летел военным самолётом до аэродрома "Чкаловский" под Москвой. Вернее, самолёт-то обычный АН-148, но принадлежит МО. Весьма доволен. Длинноногих стюардесс с коньяком не было, а в остальном очень понравилось. "Летайте самолётами ВКС России!".

Если кому интересно, могу рассказать про "Эру". Думаю, особенно студентам актуально (и родителям студентов).

Дед,

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

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Спасиба. 

Не зря я вчера зеркала расставлял перед свечами да амперсандами весь линолеум изрисовал :)  

Заглянул-таки Петрович в тему. :) 

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

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

ua6em пишет:

Он случаем не в Эра???

А где ещё?!? Но уже вернулся, вот только что домой зашёл.

Если кому интересно, могу рассказать про "Эру". Думаю, особенно студентам актуально (и родителям студентов).

Ещё бы!!!
Кстати с членкорром которого Вы тут немного попинали сообществом случаем не пересекались?

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

ua6em, простите не понял о ком речь.

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

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