функция, возвращающая структуру?

ustas
Offline
Зарегистрирован: 12.03.2012

Собственно, сабж.

Нужна фукнция, которая возвращала бы структуру.

Пример (описание структуры):

typedef struct{         
  int SensorID;        // идентификатор датчика
  int ParamID;         // идентификатор параметра 
  float ParamValue;    // значение параметра
}
Message;

Попробовал так:

Message myFun() {
  Message answer;
  ...
  return answer;
}

В результате ошибка:

'Message' does not name a type

 

Или я слишком много хочу?

ustas
Offline
Зарегистрирован: 12.03.2012

придумал "костыль":

1. Объявить глобальную переменную типа Message

2. В функции присваивать значение глобальной переменной типа Message

3. Функцию сделать с булевым результатом (0 - "не срослось", 1 - "все ок").

4. После вызова функции, если она вернула 1 - обрабатывать значения глобальной переменной.

 

Может, есть более изящное решение? 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Более правильно было бы передавать в функцию ссылку на структуру, в которой нужно менять данные.

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

Именно так, передавать указатель на структуру, типа boolean foo( struct_type *pp_struct ) Возвращать указатель на структуру - это сложнее и больше проблем, вот пример:

typedef struct Message
{
  int SensorID;        // идентификатор датчика
  int ParamID;         // идентификатор параметра 
  float ParamValue;    // значение параметра
};

Message g_msg;

void foo( Message *pp_msg )
{
  if( 5 == pp_msg->SensorID )
  {
    pp_msg->ParamID = 1;
    pp_msg->ParamValue = 18.3;
  }
  else
  {
    pp_msg->ParamID = 2;
    pp_msg->ParamValue = 2.51;
  }
}

void setup()
{
  Serial.begin( 9600 );
  g_msg.SensorID = 0;
}

void loop()
{
  g_msg.SensorID++;
  foo( &g_msg );
  Serial.print( "ParamID = " );
  Serial.println( g_msg.ParamID );
  Serial.print( "ParamValue = " );
  Serial.println( g_msg.ParamValue );
  delay( 1000 );
}

UPD: Добавил пример. Писал навскидку, могут быть нестыковки, но принцип, примерно такой.

 

Piskunov
Offline
Зарегистрирован: 13.02.2014

С Arduino познакомился с полгода назад. А недавно столкнулся с аналогичной задачей, решил ее так:

struct Msg {
          int a;
          char b;
          float c;
      };
//
struct Msg fs(){
              struct Msg temp;
              temp.a = (millis() / 1000) % 32768;
              temp.b = 'x';
              temp.c = millis() / 10000;
              return temp;
           }
//
struct Msg d;
//
void check_result(){
  Serial.println();
  Serial.print ("_int_: ");
  Serial.print (d.a);
  Serial.print (";  _char_: ");
  Serial.print (d.b);
  Serial.print (";  _float_: ");
  Serial.print (d.c);
  Serial.println();
}
void setup(){
  Serial.begin(4800);
}
void loop(){
  d = fs();
  check_result();
  delay (1000);
}

Очень хотелось бы увидеть комментарии от более продвинутых спецов.

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

В Вашем коде в строке d = fs() будет копирование локальной структуры, описанной в fs (struct Msg temp) во внешнюю структуру d. Потому, если нужно возвращать что то  большее, чем простой тип (int, byte, double и т.п.), правильней передавать указатель на эти данные (на крайний случай - ссылочный тип, но это не рекомендуется в разной литературе) и заполнять эту структуру внутри функции. Ваш вариант будет работать, но памяти он пожрет на одну структуру больше, чем нужно, а зачем, в Ардуине и так памяти кот наплакал.

С т.з. "правильности", в функцию check_result нужно также передавать указатель на структуру, тогда не потребуется глобальная структура d.

Еще, обычно не рекомендуется использовать глобальные переменные, но для Ардуины это менее критично.

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

struct Msg {
          int a;
          char b;
          float c;
      };
//
void fs( struct Msg *pp_msg )
{
              pp_msg->a = (millis() / 1000) % 32768;
              pp_msg->b = 'x';
              pp_msg->c = millis() / 10000;
}
//
void check_result( const struct Msg &p_msg )
{
  Serial.println();
  Serial.print ("_int_: ");
  Serial.print (p_msg.a);
  Serial.print (";  _char_: ");
  Serial.print (p_msg.b);
  Serial.print (";  _float_: ");
  Serial.print (p_msg.c);
  Serial.println();
}
void setup(){
  Serial.begin(4800);
}
void loop()
{
  struct Msg l_msg;
  fs( &l_msg );
  check_result( l_msg );
  delay (1000);
}

 

Piskunov
Offline
Зарегистрирован: 13.02.2014

Спасибо.

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

Функцию check_result() я использовал только для проверки работоспособности, да, надо было написать про это в коментарии - упустил :-)

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

Не совсем понял вопрос, отвечу как понял.

Каждая переменная живет ровно в своем "пространстве и времени" (scope). Можно написать, например, так:

...
{
  Msg l_msg1;
  fs( &l_msg1 );
  check_result( l_msg1 );
}
{
  Msg l_msg2;
  fs( &l_msg2 );
  check_result( l_msg2 );
}
...

здесь l_msg1 "живет" только в строках 05-08, а l_msg2 - только в 08-10. Здесь scope определяется фигурными скобками. Т.е. l_msg1 в 08-10 строках уже не существует.
Пример очень надуманный, просто продемонстрировать область видимости переменных.

Любую структуру, чтобы заполнить - нужно создать (выделить под неё место), иначе заполнять будет нечего, а когда она уже не нужна, можно её удалить/освободить.

UPD: соответственно, локальные переменные в функциях (если они не static), живут ровно на время выполнения этой функции.

 

Piskunov
Offline
Зарегистрирован: 13.02.2014

Да, ответ более полный чем вопрос.

"Чтобы задать правильный вопрос нужно знать бОльшую часть ответа"

Вы понятно объяснили, спасибо.