Fehlermeldung: 'xyz' does not name a type

Hallo,
ich habe ein kleines Testprogramm in zwei Versionen.
Einmal wird es ohne Fehlermeldung kompiliert und einmal mit. :cry:

Version 1: Variablen in extra Tab "variablen.h"
testcode.ino

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

Daten1 testwerte1;
Daten2 testwerte2;

void setup() {
  testwerte2 = testcode (testwerte1);
}

void loop() {
}

Daten2 testcode (Daten1 testzahlen) {
  testwerte2.wert1  = (testzahlen.wert1);
  testwerte2.wert2  = (testzahlen.wert2);
  testwerte2.wert3  = (testzahlen.wert3);
  testwerte2.wert4  = (testzahlen.wert4);
  testwerte2.wert5  = (testzahlen.wert5);
  testwerte2.wert6  = (testzahlen.wert6);
}

variablen.h

typedef struct Daten1{
 uint8_t  wert1;
 uint8_t  wert2;
 uint8_t  wert3;
 uint8_t  wert4;
 uint8_t  wert5;
 uint16_t wert6;
} ;

typedef struct Daten2{
 uint8_t  wert1;
 uint8_t  wert2;
 uint8_t  wert3;
 uint8_t  wert4;
 uint8_t  wert5;
 uint16_t wert6;
} ;

Diese Version wird ohne Fehlermeldung kompiliert.

Version 2: Variablen im gleichen Tab wie Programmcode
testcode.ino

#include <Arduino.h>

typedef struct Daten1 {
  uint8_t  wert1;
  uint8_t  wert2;
  uint8_t  wert3;
  uint8_t  wert4;
  uint8_t  wert5;
  uint16_t wert6;
} ;

typedef struct Daten2 {
  uint8_t  wert1;
  uint8_t  wert2;
  uint8_t  wert3;
  uint8_t  wert4;
  uint8_t  wert5;
  uint16_t wert6;
} ;

Daten1 testwerte1;
Daten2 testwerte2;

void setup() {
  testwerte2 = testcode (testwerte1);
}

void loop() {
}

Daten2 testcode (Daten1 testzahlen) {
  testwerte2.wert1  = (testzahlen.wert1);
  testwerte2.wert2  = (testzahlen.wert2);
  testwerte2.wert3  = (testzahlen.wert3);
  testwerte2.wert4  = (testzahlen.wert4);
  testwerte2.wert5  = (testzahlen.wert5);
  testwerte2.wert6  = (testzahlen.wert6);
}

Diese Version liefert folgende Fehlermeldungen:
'Daten2' does not name a type
'testcode' was not declared in this scope

Ich würde gerne die Version 2 verwenden.
Was kann/muss ich machen dass diese fehlerfrei übersetzt wird?

Danke
Gruß
Peter

Das liegt an der automatischen Prototyp Erzeugung der IDE. Wenn du structs als Parameter verwendest, erstellt die IDE einen Funktions-Prototyp und schreibt diesen ganz oben hin. Wo das struct nicht bekannt ist. Die Lösung ist den Prototyp einfach per Hand zu erstellen.

Wobei sonst noch zwei Sachen nicht passen:
1.) Komplexe Datentypen wie structs übergibt man als Referenz! Sonst wird eine Kopie erstellt
2.) Deine Funktion hat einen Rückgabewert, aber gibt nichts zurück

Punkt 2 lässt sich auch einfach umgehen wenn du Punkt 1 umsetzt. Dann sind Änderungen in der Funktion sowieso nach außen sichtbar

Ich schließe mich mal Serenifly an und frage zusätzlich: Welche IDE verwendest du??? In Versionen unter 1.6.9 kommt es in der Tat zu den o.g. Fehlern inkl. Abbrüchen; in der Version 1.6.9 wird das Programm zwar kompiliert, wirft aber eine Menge Warnungen heraus, die die Aussagen von Serenifly unterstützen.

Normal macht man es so:

struct Data
{
   ...
};

void func(Data& data);

void setup()
{
   Data data;
   func(data);
}

void loop()
{
}

void func(Data& data)
{
   data. ... = ...;
}

Letztens wurde mal der Prototyp-Parser verbessert. Aber ob er inzwischen mit struct-Parametern umgehen kann weiß ich nicht. Ist möglich wenn es in einer neueren Version ohne Fehler kompiliert. Aber die Warnung sollte man aktivieren und beachten! Das mit dem Rückgabe-Wert produziert zwar keine Fehler, aber manche Warnung wie diese sind praktisch schon Fehler.

Herzlichen Dank für die Hilfen.

Als IDE verwende ich die 1.6.5.

Ich habe jetzt versucht die Tipps aus #3 umzusetzen und das Ganze etwas gekürzt weil es nur um das Prinzip geht.

Jetzt sieht es so aus.

struct_test_03.ino

#include <Arduino.h>

struct Daten1 {
  uint8_t  wert1;
  uint16_t wert2;
};

struct Daten2 {
  uint8_t  wert1;
  uint16_t wert2;
};

Daten1 testwerte1;
Daten2 testwerte2;
  
void testcode (Daten1& testwerte1);

void setup() {
  testcode (testwerte1);
}

void loop() {
}

void testcode (Daten1& testzahlen) {
  testwerte2.wert1  = (testzahlen.wert1);
  testwerte2.wert2  = (testzahlen.wert2);
}

Folgende Fehlermeldungen bekomme ich:
struct_test_03:6: error: variable or field 'testcode' declared void
struct_test_03:6: error: 'Daten1' was not declared in this scope
struct_test_03:6: error: 'testzahlen' was not declared in this scope
variable or field 'testcode' declared void

Wo liegt denn nun der Hund begraben?
Das einzige was ich wissentlich gegenüber #3 geändert habe ist, dass die Variablen global statt lokal in setup() deklariert sind.

Gruß Peter

Bei mir geht es. Ist aber 1.6.9. Wobei es da auch ohne Prototyp geht :slight_smile: Dann scheint diese Änderung in 1.6.7 doch was gebracht zu haben:

New arduino-builder: faster, better prototype generation

Früher ging das ohne korrekten Prototyp nie

Genaugenommen sollte es aber so sein:

void testcode (Daten1& testzahlen);

Weiß nicht ob der Parameter-Name einen Unterschied macht. Manchmal wird er auch ganz weggelassen (was wieder mal historisch aus den C-Urzeiten kommt).

Aber bei dir könnte er da jetzt durcheinander kommen weil du plötzlich einen Namen angibst der schon für ein Objekt vergeben ist

Es ist übrigens auch nicht toll ein struct als Parameter zu übergeben und es dann in ein globales zu kopieren. Am konsequentesten wäre es beide als Parameter zu übergeben (nach dem üblichen Ziel/Quelle Prinzip). Am einfachsten wäre statt dessen memcpy() zu verwenden. Dann geht es ganz ohne eine eigene Funktion

peter_de:
n/muss ich machen dass diese fehlerfrei übersetzt wird?

Was soll das Programm denn machen, wenn es fehlerfrei übersetzt wird?
Das Programm enthält so offensichtliche und schwerwiegende Fehler, dass es nicht nur nicht fehlerfrei compiliert werden kann, sondern dass ich nicht mal erkennen kann, was das Programm machen soll.

Üblicherweise dienen dazu Kommentare im Quelltext.

Erster Rateversuch: Soll das eine Übung werden mit dem Thema "wie man mit wenigen Zeilen Code möglichst viel Quatsch programmiert"?

Ich mache noch einen zweiten Rateversuch;

Möchtest Du den Inhalt einer struct-Variablen in eine andere struct-Variable hineinkopieren?

Wenn mein zweiter Rateversuch dichter dran ist, dann informiere Dich über die Standardfunktion memcpy, beschrieben auf
http://en.cppreference.com/w/cpp/string/byte/memcpy

Es ist übrigens auch nicht toll ein struct als Parameter zu übergeben und es dann in ein globales zu kopieren.

Ich wollte es gerade auch schon schreiben; irgendwie ist das nämlich in meinen Augen Unfug, der sich von hinten durch die Brust ins Auge schießt. Wenn ich schon irgendwelche Variablen oder Structs "global" definiere, kann ich auch direkt "global" damit arbeiten - ohne das Gehampel mit Funktions-Parameter etc. So im Sinne von:

struct Daten1 {
  uint8_t  wert1;
  uint16_t wert2;
};

struct Daten2 {
  uint8_t  wert1;
  uint16_t wert2;
};

Daten1 testwerte1;
Daten2 testwerte2;
 
void testcode();

void setup()
{ testcode(); }

void loop()
{}

void testcode()
{
  testwerte1.wert1 = testwerte2.wert1;
  testwerte1.wert2 = testwerte2.wert2;
}

Man sollte aber auch mal lernen wie man das ohne globale Variablen macht. Es kommt z.B. auch oft vor dass man eine Funktion braucht die ein struct als Parameter hat das dann von irgendwo mit Daten befüllt wird, z.B. Werte von einem Sensor oder der Inhalt einer Datei von einer SD Karte.

Das sauberste ist wie gesagt einfach memcpy():

memcpy(testwerte1, testwerte2, sizeof(testwerte1));

Ich hatte bei der Übergabe eines Struct-Pointers in der IDE 1.6.5 auch Pobleme, wenn ich das Schlüsselwort struct weggelassen habe.

Beispiel:

// Werte zuur Steuerung einer Farbe
typedef struct t_farbe {
  byte pin;
  byte hell;
  int8_t delta;
  byte start;
  byte ziel;
  byte wdh;
  uint32_t intervall;
  uint32_t prevMillis;
};

Nutzung (kompiliert)
// bestimmt den Delta-Wert für Fading
byte calcDelta(struct t_farbe *f) {
  if (f->ziel == f->start) return 0;
  if (f->ziel > f->start) return 1;
  return -1;  
}

kompiliert nicht:
// bestimmt den Delta-Wert für Fading
byte calcDelta(t_farbe *f) {
  if (f->ziel == f->start) return 0;
  if (f->ziel > f->start) return 1;
  return -1;  
}

Es scheint, dass ihm das struct im Aufruf irgendwie hilft.

Gruß Tommy

@Thommy56
Als "alter Hase" sollte dir doch bekannt sein, Sketche lassen sich in Code-Tags besser lesen.

HotSystems:
@Thommy56
Als "alter Hase" sollte dir doch bekannt sein, Sketche lassen sich in Code-Tags besser lesen.

Asche auf mein Haupt. Korrigiert.

Gruß Tommy

Tommy56:
Asche auf mein Haupt. Korrigiert.

Gruß Tommy

Prima, danke.

Hallo,
und Entschuldigung dass ich hier etwas Verwirrung gestiftet habe.

Ich glaube ich muss zur Klarstellung etwas weiter ausholen.
Mein eigentlicher Sketch geht über 11 Tabs und belegt ca.95kB im Programmspeicher eines MEGA2560.
Ich glaube den will hier niemand sehen sonst wird die Verwirrung noch größer. :grin:
Das Programm wird mit der IDE 1.6.5 fehlerfrei übersetzt und läuft auch problemlos.

In einem dieser 11 Tabs sind mehrere struct-Variablen definiert. Diesen Tab wollte ich eliminieren indem ich diese Variablen an der Stelle deklariere an der auch alle anderen globalen Variablen deklariert sind.

Um das Problem vereinfacht darzustellen habe ich im Eingangspost versucht einen Beispielcode (ohne sittlichen Nährwert) zu zeigen der das eigentliche Problem kurz und bündig beschreibt. Das hat jetzt leider auch zu den memcpy() Lösungen geführt. Sorry deswegen. memcpy() passt im realen Sketch nicht. Dort geht es nicht darum eine struct-Variable in eine andere zu kopieren.

Ich glaube irgendwo mal gelesen zu haben, dass man struct-Variablen, wenn sie mal deklariert sind, im Programm so verwenden kann wie int oder float ect. Das funktioniert in der Arduino-IDE dann scheinbar doch nicht so wie gedacht und verhält sich bei verschiedenen IDE-Versionen wohl auch noch unterschiedlich.

Ich will halt einfach nur diesen (lästigen) Tab mit den struct-Variablen, der im "Hauptprogramm.ino" includiert wird los werden.

Diese struct-Variablen werden zum Teil als Parameter an Funktionen übergeben zum Teil greifen aber auch andere Funktionen auf die global deklariert Variablen direkt zu. Darum auch die globale Deklaration der struct-Variablen im Eingangspost.

Ich bin halt auch nicht der große Programmiermeister und deshalb entstehen manchmal solche "unseriösen" Konstruktionen, zum Teil (wie auch in diesem Fall) durch copy&paste von irgendwo gefundenem fertigem Code.

Ich glaube ich lasse den Tab mit den struct-Variablen einfach weiterhin bestehen, denn eine einfache Lösung, wie ich dachte, die mit allen IDE-Versionen harmoniert scheint es nicht zu geben.
So wird mein Beispiel in Version 1.6.9 fehlerfrei übersetzt und mit meiner 1.6.5 läuft es auch nicht wenn ich Funktionsprototypen anlege.
Mit den in einen Tab ausgelagerten struct-Variablen klappte es schon mit der IDE 1.0.6, der 1.5.x und jetzt auch mit der 1.6.5.

Gruß Peter

Das Problem im Zusammenhang mit Funktionen ist wie gesagt in erster Linie die automatische Prototyp Generierung. Wenn die IDE Funktions-Prototypen generiert, werden (oder wurden?) die ganz oben hingeschrieben wo das struct noch nicht deklariert wurde. Dann beschwert sich der Compiler natürlich dass er das nicht kennt. Wenn man den Prototypen per Hand hinschreibt umgeht man das.

Bei Tabs ändert sich vielleicht die Reihenfolge in der das vor dem Compilieren zusammenkopiert wird.

Richtig .cpp und .h Dateien zu verwenden statt einfach nur .ino Tabs würde auch helfen. Auch daran denken dass Tabs in alphabetischer Reihenfolge abgearbeitet werden! Es ist also u.U. möglich in einem Tab etwas verwenden zu wollen, dass da noch noch nicht bekannt ist. Das kann man auch umgehen wenn man die Datei für die globalen Variablen z.B. "aGlobal.ino" nennt (sofern nicht doch noch was anderes davor kommt)

An dem was Tommy56 geschrieben hat ist auch was dran. Das struct keyword sollte an der Stelle eigentlich nur in C nötig sein und nicht in C++ (die Sprachen unterscheiden sich da), aber ich hatte glaube ich auch schon ein paar Fälle wo es solche Probleme gelöst hat.

Ich habe den Vorschlag von Tommy56 auch ausprobiert. Das hat aber ebenfalls nichts gebracht.

Dann habe ich das Programm das mit der IDE1.6.5 lauffähig übersetzt wird mit der Version 1.6.9 und 1.6.11 übersetzt. Das Ergebnis ist, dass ich bei beiden Versionen vom Fehlermeldungen erschlagen werde.

Meine Erkenntnis daraus ist, dass ich einen besch... Programmierstil habe und den grundlegend ändern muss um künftig mit den neueren IDE-Version lauffähige Programme zu erhalten.

Damit ich jetzt nicht auch noch zusätzlich mit Fehlern in der IDE kämpfen muss eine Frage an die Allgemeinheit.
Welche IDE von .cc ist nach der 1.6.5 die empfehlenswerte weil "fehlerfrei" ?

Gruß, Peter

"fehlerfrei"

Naja...
Solange Menschen daran arbeiten ....

Meine Erkenntnis daraus ist, dass ich einen besch... Programmierstil habe und den grundlegend ändern muss um künftig mit den neueren IDE-Version lauffähige Programme zu erhalten.

Hört sich gruselig an, dass muss ich sagen, und ein Kern Wahrheit steckt da auch drin.

Auch wenn es dir nicht direkt weiter hilft:
Wissen + Disziplin = gutes Programm

Danke @combie für die aufmunternden Worte. :smiley:
Wissen muss ich noch zusammentragen, bei der Disziplin gebe ich mir Mühe.

Ich versuche gerade Code aus der "alten" Version in der IDE 1.6.11 neu zu gestalten.
Dazu habe ich verschiedene Tabs angelegt um etwas Struktur in die Sache zu bringen.

U.A. gibt es die Tabs "Setup.cpp", "Setup.h", "LCD.cpp" und "LCD.h".

In "Setup.cpp" steht:

LiquidCrystal_I2C lcd(0x27, 20, 4);
...
lcd.print("xyz...");

Das funktioniert soweit.

In "LCD.cpp" stehen weitere Ausgaben auf das Display. Z.B:lcd.setCursor(0, 2);Dazu gibt es dann aber die Fehlermeldung: error: 'lcd' was not declared in this scope
Das kann ich soweit auch verstehen weil das Objekt? lcd in "LCD.cpp" nicht bekannt ist.

Wie muss ich das handhaben. Wie kann ich lcd in "LCD.cpp", oder besser global, bekannt machen?

Gruß Peter

"LCD.h"

#pragma once
extern LiquidCrystal_I2C lcd;

"LCD.cpp"

#include "LCD.h"

LiquidCrystal_I2C lcd(0x27, 20, 4);
//...
void tuwas()
{
  lcd.print("xyz...");
}

oder besser global, bekannt machen?

Wieso "oder"?
Warum nicht "und"?

"test.ino"

#include "LCD.h"

void loop()
{
  lcd.print("abc...");
}

Die Tabs werden in alphabetischer Reihenfolge in eine .cpp Datei kopiert und dann compiliert! Und L kommt vor S

Eine Möglichkeit sind wie oben gezeigt Header Dateien. Oder man packt die Variablen Deklarationen in eine Datei die alphabetisch am Anfang kommt.