[erledigt] variable or field 'turn' declared void

Hallo allerseits!

Ich schlage mich seit gut einer Stunde mit einem Fehler, den ich auch nach dem Lesen einiger Seiten (sowohl hier im Forum als auch außerhalb) nicht klären konnte.

Ein sehr kurzes und sinnfreies Programm, das diesen Fehler provoziert:

// test

enum dir{LEFT,RIGHT};

void setup()
{
}

void loop()
{
}

// eof

und

// turn()

void turn(dir dir_)
{
  switch(dir_)
  {
    case LEFT:
      // tuwas
      break;
    case RIGHT:
      // tuwas
      break;
  }
}

// eof

Wieso erhalte ich beim Verifizieren des Codes den Fehler „error: variable or field ‘turn’ declared void“?

Vielen Dank vorweg!

Gregor

PS: Ein auf die Schnelle eingetipptes Programm, das von g++ anstandslos übersetzt wird …

// main.cc

#include "main.hh" // ist leer
#include <iostream>

enum foo{LINKS, RECHTS};

using namespace std;

void bar(foo foo_)
{
  cout << "[bar()] foo_ ist '" << foo_ << "'" << endl;
}

int main(int argc, char** argv)
{
  cout << "[main()] bar(LINKS) wird aufgerufen ..." << endl;
  bar(LINKS);
  cout << "[main()] bar beendet." << endl;

  cout << "[main()] bar(RECHTS) wird aufgerufen ..." << endl;
  bar(RECHTS);
  cout << "[main()] bar beendet." << endl;

  return(0);
}

// eof

… und läuft, wie erwartet. Bin ich auf eine der Arduino-Besonderheiten getreten?

Die IDE ärgert dich weil sie die Protypen per Hand erstellt und diese ganz oben hinschreibt wo das enum nicht bekannt ist.

Erstelle für die Funktionen mit enum Parametern die Prototypen selbst und schon geht es

Serenifly:
Die IDE ärgert dich ...

Ungefähr das habe ich vermutet. Problematisch ist das wohl besonders in Verbindung mit dem enum: Wenn das 'enum' vor dem Prototypen steht, bekomme ich die Fehlermeldung im Betreff, wenn es andersrum steht, meckert er, weil im Prototypen ein unbekannter Datentyp steht.

Ich habe jetzt die enum-Werte per #define gesetzt und den Datentyp des Funktionsparameters auf bool.

So funktioniert’s. Danke für den Hinweis!

Gruß

Gregor

gregorss:
Ich habe jetzt die enum-Werte per #define gesetzt und den Datentyp des Funktionsparameters auf bool.

C enums sind normal int. Daher kann man auch einen Integer als Parameter nehmen

Aber die korrektere Lösung wäre eben die Prototypen per Hand zu machen:

void turn(dir dir_);

Das nachdem das enum definiert wurde, dann ist das auch an der Stelle bekannt. Wenn du das weiterhin über das enum schreibst geht es natürlich immer noch nicht.

Die IDE macht das draus:

void turn(dir dir_);

enum dir{LEFT,RIGHT};

Und er Compiler meckert dass er dir nicht kennt

Serenifly:
... Aber die korrektere Lösung wäre eben die Prototypen per Hand zu machen:

void turn(dir dir_);

Das nachdem das enum definiert wurde, dann ist das auch an der Stelle bekannt. Wenn du das weiterhin über das enum schreibst geht es natürlich immer noch nicht.
...

Genau das stimmt leider nicht. Siehe oben. Entweder meckert der Compiler, dass 'dir' ein ungültiger Datentyp sei – oder er beschwert sich in der Weise, wie es im Betreff steht.

Gruß

Gregor

Bei mir geht es (1.6.5)

enum direction { LEFT, RIGHT};

void func(direction dir);

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

  func(LEFT);
  func(RIGHT);
}

void loop()
{
}

void func(direction dir)
{
  Serial.println(dir);
}

Bei mir auch.
Die IDE erstellt die Prototypen nur, wenn ich sie nicht selber erstelle.

@gregorss
Unterscheide zwischen der Deklaration und der Definition einer Funktion/Variable.
Der Prototyp, einer Funktion, ist eine Deklaration.
Korrekter: Die Vorwärtsdeklaration einer Funktion

Serenifly:
Bei mir geht es (1.6.5)

Ups?! 1.6.5 läuft auch bei mir.

Soeben probiert: Dein Code wird compiliert, mein Code aus dem OP bringt immer noch die gleichen Fehlermeldungen. Liegt es möglicherweise daran, dass Du alles in einer Datei stehen hast? Könntest Du mal testen, ob mein Code aus dem OP bei Dir compiliert?

Gruß

Gregor

Bei mir (1.6.5) geht Serenifly's Version auch, aber Gregors zeigt den gleichen Fehler !

enum dir {NONE, LEFT, RIGHT};
void turn(dir);

void setup() {
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
}

void loop() {
      turn (LEFT);
      delay(1000);
      turn (RIGHT); 
      delay(1000);
}

void turn (dir d) {
  switch (d) {
    case LEFT:  digitalWrite(12, HIGH); break;
    case RIGHT: digitalWrite(13, HIGH); break;
    default:
      digitalWrite(12, LOW);
      digitalWrite(13, LOW);
  }
}

sketch_feb23b.ino:4:12: error: variable or field 'turn' declared void
sketch_feb23b.ino:4:12: error: 'dir' was not declared in this scope
variable or field 'turn' declared void

Sehr merkwürdig!

Abhilfe / Workaround : Die ersten zwei Zeilen in eine include Datei auslagern.

Ja, das ist sehr komisch :confused: Ich sehe nicht was da groß unterschiedlich sein soll.

Der Fehler deutet auf einen Fehler mit dem Parameter hin, so dass der Parser das für eine Variable hält und nicht als Funktion erkennt.

Man kann auch einfach aus dem Parameter einen int machen und bei dem enum bleiben. Wenn man will das sich enums wie richtige Datentypen verhalten dann muss man sowieso C++11 strongly typed enums verwenden.

mein Code aus dem OP bringt immer noch die gleichen Fehlermeldungen.

Ich sehe da keine Prototypen...
Bin ich blind?

Im OP nicht, das stimmt, aber mein Beispiel zwei Einträge vorher, hat sogar Serenifly überzeugt :wink:
Ist nicht so einfach, die IDE dazu zu bringen, keinen Unsinn zu machen...

dir.h

#ifndef _DIR_H
#define _DIR_H
enum dir {NONE, LEFT, RIGHT};
void turn(dir);
#endif

und #include "dir.h" im sketch hilft übrigens.

Ansonsten heisst die erzeugte sketch.cpp im tmp Verzeichnis:

#line 1 "sketch_feb23b.ino"
#include "Arduino.h"
void setup();
void loop();
void turn (dir d);
#line 1
enum dir {NONE, LEFT, RIGHT};
void turn(dir);

void setup() {
...

Pech aber auch...

Ok. Fehler gefunden! Dass zwei Prototypen erzeugt werden hatte ich mir schon gedacht. Ich hatte den Parser aber für so intelligent gehalten mit Leerzeichen umgehen zu können.

Korrekt:

void turn (dir d);

void turn (dir d)
{
}

Falsch:

void turn(dir d);

void turn (dir d);
{
}

Der Prototyp muss wirklich 1:1 zu übereinstimmen. Wenn bei der Definition ein Leerzeichen ist muss das auch beim Prototyp vorhanden sein. Wenn nicht, darf auch im Prototyp keines stehen.

EDIT: so passt es jetzt glaube ich. Habe das Beispiel so gemacht dass die Funktion ein Leerzeichen hat

combie:
Bin ich blind?

Nein, Du hast recht. Ich hatte mich wohl verklickt.

So einem Zeug hinterher zu jagen, macht manchmal ein bisschen blöd :slight_smile:

Gruß

Gregor

PS: Immerhin bin ich nicht der Einzige, den das irritiert. Beruhigend ...

Der Prototyp muss wirklich 1:1 zu übereinstimmen. Wenn bei der Definition ein Leerzeichen ist muss das auch beim Prototyp vorhanden sein. Wenn nicht, darf auch im Prototyp keines stehen.

Bei der 1.6.7 ist das offensichtlich nicht mehr so.
Da kompiliert die Variante aus #8 problemlos.

Ich hatte auf Github gelesen dass man den Prototyp Parser überarbeitet hat. Aber ich weiß nicht genau wie. Da stand auch was dass in Zukunft vielleicht Default Parameter gehen würden, wenn auch nicht ganz wie üblich (normal ist der Default Wert im Prototyp).

In den Release Notes steht es auch:

New arduino-builder: faster, better prototype generation ...

Aber keine Details

Ist nicht so einfach, die IDE dazu zu bringen, keinen Unsinn zu machen...

...aber du hast es geschafft.
Herzlichen Glückwunsch, Serenifly.

Wird Zeit für die 1.6.7 (jetzt, wo dieser Haken der 1.6.5 im Griff ist)