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

axill
Offline
Зарегистрирован: 05.09.2011

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

У меня скетч разбит на несколько файлов, в одном есть такое:

char sdlog_buf[100];

inline char* sdlogBuf() { return sdlog_buf; }

в другом:

static void utft_statusIP(uint32_t ip) {
  char buf[20];
	uint8_t *bytes = (uint8_t*)&ip;

	myGLCD.setBackColor(0, 255, 0);
	myGLCD.setColor(0, 0, 0);
	sprintf(sdlogBuf(), "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
	myGLCD.print(sdlogBuf(), UTFT_STATUS_XMIN, UTFT_STATUS_YMIN);
	myGLCD.setBackColor(0, 0, 0);
}

так вот если откомментировать строку с myGLCD.print то ри попытке прошить скетч начинают сыпаться ошибки averdude, а если ее закомментировать - нет проблем. Так же не будет проблем если буфер объявить внутри файла и обращаться к нему напрямую. Мне показалось лучше иметь один большой буфер чем много раз их объявлять - это жкономит ресурсы и не требует динамического выделения. Не понимаю в чем подстава, вроде обращение в массиву через функуцию ничем не отличается

leshak
Offline
Зарегистрирован: 29.09.2011

А зачем тут вообще функция? Почему sdlog_buf напрямую не использовать?

Чем

myGLCD.print(sdlog_buf, UTFT_STATUS_XMIN, UTFT_STATUS_YMIN);

не устраивает?

axill
Offline
Зарегистрирован: 05.09.2011

leshak пишет:

А зачем тут вообще функция? Почему sdlog_buf напрямую не использовать?

Чем

myGLCD.print(sdlog_buf, UTFT_STATUS_XMIN, UTFT_STATUS_YMIN);

не устраивает?

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

leshak
Offline
Зарегистрирован: 29.09.2011

Чудно. Что-то вы не договариваете. Функция значит видна, а переменная нет? Как так? Или функция тоже не видна и проблема в этом? Может и ошибки сыпятся на из avrdude?  (ему-то что? он вообще взял бинарник и послал его... в его суть - он не вникает).

Это раз. Во вторых, может направится в сторону того что-бы "переменная стала видна"?

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

А именно что значит "разбита на закладки?". То есть "понятно", но ведь тоже много вариантов. Смотря на кикие именно файлы. На .ino, на .cpp, на .h  . Они хоть и выглядят во вкладках "похоже", но ведь компилируются/линкуются весьма по разному (и скажем честно, у ардуины иногда - действительно бывают "магические заглюки" в процессе этого).

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

1. Вынести вашу переменную в отдельный .h и инклудить его туда где она требуется (это как-бы сишный путь)
2. Пихать ее в повыше в главный скетч. Следить за тем в каком порядке ArduinoIDE объединяет .ino файлы (если не ошибаюсь - тупо в алфавитном)
3. Воспользоваться ключевым словом extern   (пообещать компилятору/линкеру, что "где-то в других файлах" у нас будет объявлена эта переменная).

leshak
Offline
Зарегистрирован: 29.09.2011

Вообщем вариант (2) - я не люблю. Привязывать компилируемость програмы к именам файла - бу-э. Как и засорять главный скетч.

Вообщем попрбуйте такие варианты:

Вариант (1):

Создаем в папке файл с именем CommonVars.h

В него

#ifndef common_vars_h
#define  common_vars_h

#define LOG_BUF_LEN 100 // размер буффера

char sdlog_buf[LOG_BUF_LEN]; // сам буфер

#endif

Заодно и размеру буфера дали имя. Пригодится если где-то в коде нужно будет проверять (а не превысили-ли мы ...)

Ну а потом, везеде где вам потребовался буффер делаете

#include "CommonVars.h"

и пользуетесь свои буфером.

Вариант 3:

Вверху второго файла (который с myGLCD) пишите:

extern char sdlog_buf[100]; // второй раз память не выделится. это только обещание что где-то такая переменная с таким именем

-----

Если у вас таких "общих переменных" всегод одна. Вариант (3) будет, наверное проще. Но это "костыль". Если же вы планируете и дальше использовать что-то общее (переменные, константы, типы),  тогда Вариант 2 однозначно. Подключил один файлик - и у тебя все есть :)

axill
Offline
Зарегистрирован: 05.09.2011

leshak пишет:

Чудно. Что-то вы не договариваете. Функция значит видна, а переменная нет? Как так?

если бы я знал ответ, я бы не спрашивал, именно! функция видна, а переменная нет)) что вы меня сразу во всех грехах обвиняете?) сам прекрасно знаю, что правильный ответ это на 80% правильно заданный вопрос. Ничего я не утаиваю - в начале темы указано про то, что проект разбит на файлы. Как раз если добавлять "закладку" (стрелочка вниз слева вверху окна редактирования) то вариант расширения файла будет один - .ino.

Цитата:

Или функция тоже не видна и проблема в этом? Может и ошибки сыпятся на из avrdude?  (ему-то что? он вообще взял бинарник и послал его... в его суть - он не вникает).

самому странно) но факт 100%!!! проверял много раз. стоит разкоментировать строку где есть вызов функции как после этого я не могу залить скетч!

Цитата:

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

1. Вынести вашу переменную в отдельный .h и инклудить его туда где она требуется (это как-бы сишный путь)
2. Пихать ее в повыше в главный скетч. Следить за тем в каком порядке ArduinoIDE объединяет .ino файлы (если не ошибаюсь - тупо в алфавитном)
3. Воспользоваться ключевым словом extern   (пообещать компилятору/линкеру, что "где-то в других файлах" у нас будет объявлена эта переменная).

пробовал все, если включать один и тот же файл в разные "закладки" позникает конфликт. Тоже происходит если использовать extern.

На самом деле вы наверно правы - ардуино "тупо" склеивает все файлы проекта в один в том порядке в котором они отображатся в окне редактиврования. Я вставил определение буфера в самый левый файл и она стала видна в других "закладках"

спасибо за подсказки

leshak
Offline
Зарегистрирован: 29.09.2011

axill пишет:

пробовал все, если включать один и тот же файл в разные "закладки" позникает конфликт. Тоже происходит если использовать extern.

Ну если вы "пробовали все" - то тогда "ничем не поможешь".

Но я бы, все-таки, рекомендовал попробовать вариант c .h файлом. Именно с таким именем и таким расширением как я написал. И не выкидывать из него ничего (особенно первый две и последнюю строку). Тогда никаких конфликтов от многократного включения - не должно быть.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Категорически не соглашусь с вариантом, когда в .h файле объявляются переменные. В таких файлах максимум можно описать внешние переменные со словом extern. Сами переменные нужно объявить в подходящем .cpp (ino) файле. Спорить не хочу и не вижу смысла.

Один из вариантов (leshak, я взял за основу твои исходники):

Файл foo.h:

#pragma once

#ifndef foo_h
#define  foo_h

#define LOG_BUF_LEN 100 // длина буфера

extern char sdlog_buf[LOG_BUF_LEN]; // описание внешнего буфера

extern void init_buffer(); // инициализация буфера, это функция

#endif

Файл foo.ino:

#include "foo.h"

char sdlog_buf[LOG_BUF_LEN]; // сам буфер

void setup()
{
  init_buffer();
}

void loop()
{
  if( sdlog_buf[ 1 ] == 'A' )
  {
  }
}

Файл foo2.cpp:

#include "foo.h"

void init_buffer()
{
  sdlog_buf[ 0 ] = '\0';
}

.h файлы предназначены только для описания чего то, а не для объявления объектов, переменных и т.п.

Пример, что я привел - компилируется, я проверил.

 

leshak
Offline
Зарегистрирован: 29.09.2011

kisoft пишет:

Спорить не хочу и не вижу смысла.

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

Хотя, в данном случае, спорить-то особо никто и не собирался :)   .  Я тоже стараюсь всегда связку h/cpp использовать (ну хотя бы потому, что потом легче в виде библиотеки оформить). Но... как "быстрое решение проблемы" переменная в .h - тоже работает. Проверенно :)  Но, конечно, это "нарушение идиологического духа". Никто спорить не будет :) Ваш вариант - кошерней :)

А вот по поводу "#pragma once" - возможно стоило бы. Цитата из вики:

В языках программирования Си и C++ #pragma once — нестандартная, но широко распространенная препроцессорная директива, разработанная для контроля за тем, чтобы конкретный исходный файл при компиляции подключался строго один раз. То есть, #pragma once применяется для тех же целей, что и include guard, но требует меньше кода и не допускает возможности коллизии имён. Считается устаревшей и для применения не рекомендуется

К тому же "include guard" - я уже написал (хе-хе, не знал что эта конструкция имеет свое название). Так что две конструкции для одного и того же - явно избыточны. Тем более, что

С другой стороны, некоторые компиляторы, как например, GCC, также используют специальный код для распознавания и оптимизации обработки include guard.[1]

Так что "две конструкции сразу" имели бы смысл только если мы бы планировали этот код компилировать какими-то неведомыми компиляторами.

axill
Offline
Зарегистрирован: 05.09.2011

leshak пишет:

Ну если вы "пробовали все" - то тогда "ничем не поможешь".

так уже помогли)) переменную надо объявлять в файле самом левом

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

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

leshak, спорить не вижу смысла, потому что опыт программирования у меня достаточный, он и подсказывает.
На счет pragma, просто привычка, потому что мне приходиться компилировать разными компиляторами одни и те же исходники. Поскольку и то и другое не противоречит, пишу и то и другое. Здесь, наверное, это излишество.

leshak
Offline
Зарегистрирован: 29.09.2011

kisoft пишет:
leshak, спорить не вижу смысла, потому что опыт программирования у меня достаточный

Я не хочу сказать что у вас нет опыта (при этом все равно есть шансы натолкнутся на новинку или неочевидный нюанс). Его наличие - очевидно из самой сути вашего замечания. Возможно даже поболее моего (все-таки C/C++ для меня "не родные", до ардуины я на них в школе один hello world написал :) и это было давно, уже с ардуиной пришлось вспоминать  "как оно жить без GarbageCollector-а" :) . Тут скорее сам ваш речевой оборот, скажем так... задевает :) И вызывает прямо противоположную реакцию.

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

А то что формально вы правы - так я сразу признал. Ну поленился я. Что я, не человек?  ;)

leshak
Offline
Зарегистрирован: 29.09.2011

axill пишет:

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

Еще как собирает. Вы файлам дайте расширение "как принято" .h/.cpp - будет вам линковка. А .ino - принято склеивать. Так что у вас полная свобода выбора "как вам проект собирать" :) Ну разве что, не помню, можно ли прямо из ArduinoIDE файлу расширение сменить. Но, в крайнем случае, мы и без ArduinoIDE файлы создавать умеем :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Если сделать как в моем примере, то неважно, склейка будет или нет, ошибок компиляции не будет.