www.mikrocontroller.net

Forum: Compiler & IDEs eigener Variablentyp


Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ich programmiere gerade die Routinen für einen AD9833 DDS 
(Signalerzeuger) Baustein.

Dabei möchte ich eine Prozedur schreiben die in etwa folgenden Prototyp 
hat:

void dds_SetWaveForm(dds_WV WaveForm);

dds_WV soll letztenendes nur ein uint8_t sein alledings möchte ich das 
man keine Zahl direkt reinschreiben darf sondern nur:
dds_WF_Sin
dds_WF_Tri
dds_WF_Rect

die dann wie folgt definiert sind:
#define dds_WF_Sin 0x00;
#define dds_WF_Tri 0x02;
#define dds_WF_Rect 0x28;


Ich weiß ich könnte jetzt auch z.B. dds_SetWaveFrom(dds_WF_Sin) machen 
wenn ich WaveFrom (s. Prototyp) als uint8_t angebe. Aber ich will halt 
verhindern, dass man aus versehen eine (falsche) Zahl reinschreiben 
kann. Und nur die drei o.A. angaben zulassen -> sonst fehler: 
inkompatible typen
Wie kann ich das in avr-gcc anstellen?

Vielen Dank

Dirk

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:

> Wie kann ich das in avr-gcc anstellen?

Die schlechte Nachricht ist: gar nicht

Die etwas bessere Nachricht ist: mit einem enum
enum WaveForms { dds_WF_Sin, dds_WF_Tri, dds_WF_Rect };

void dds_SetWaveForm( enum WaveForms form );

int main()
{
  SetWaveForm( dds_WF_Sin );
}

allerdings kann dich C nicht davor schützen, dass sich ein Programmierer 
einen ungültigen Wert zusammencastet.
int main()
{
  SetWaveForm( 5 );                     // <- das gibt einen Fehler
  SetWaveForm( (enum WaveForms)5 );     // <- aber das geht durch den Compiler
}

Zumindest hast du so beim Funktionsprototypen dokumentiert, dass du nur 
bestimmte Werte haben möchtest und welche das sind.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:
> #define dds_WF_Sin 0x00;
> #define dds_WF_Tri 0x02;
> #define dds_WF_Rect 0x28;
Das ist syntaktisch falsch, ein #define wird (wie alle 
Präprozesoranweisungen) nicht mit einem Semikolon abgeschlossen. Ich 
hoffe, in Deinem Programm machst Du das nicht so...

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich es richtig verstanden habe: Kannst du in deiner Funktion eine 
Switch case oda if-else Abfrage machen:

z.b:


void dds_SetWaveForm(dds_WV WaveForm)
{

   switch(WavForm)
   {
       case dds_WF_Sin:
                 ......break;
       case dds_WF_Tri:
                 ......break;
       case dds_WF_Rect:
                 ......break;
       default: Error break;


    }



}
Oder du kannst es gleich überprüfen bevor du deine Variable der Funktion 
übergibst, ob sie gültig ist.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Dirk wrote:

>> Wie kann ich das in avr-gcc anstellen?
> Die schlechte Nachricht ist: gar nicht

Wieso "gar nicht"? Du erklaerst doch danach, wie es geht?

> allerdings kann dich C nicht davor schützen, dass sich ein Programmierer
> einen ungültigen Wert zusammencastet.

Was dann ja kein Versehen mehr waere, sondern Absicht und gegebenenfalls 
Bloedheit...

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Dirk wrote:

> Das ist syntaktisch falsch, ein #define wird (wie alle
> Präprozesoranweisungen) nicht mit einem Semikolon abgeschlossen. Ich
> hoffe, in Deinem Programm machst Du das nicht so...

Syntaktisch ist das durchaus richtig und manchmal auch sinnvoll. Man 
darf nur nicht vergessen, dass das Semikolon Teil der Ersetzung ist und 
dann eben auch an der Stelle landet, wo das define verwendet wird...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Stegemann wrote:
> Karl heinz Buchegger wrote:
>> Dirk wrote:
>
>>> Wie kann ich das in avr-gcc anstellen?
>> Die schlechte Nachricht ist: gar nicht
>
> Wieso "gar nicht"? Du erklaerst doch danach, wie es geht?

Ich zeig ihm aber auch, wie man bewusst diesen vermeintlichen Schutz 
aushebeln kann.
In C ist das so. In anderen Sprachen nicht. Dort sind Aufzählungstypen 
restriktiver.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Stegemann wrote:

> Was dann ja kein Versehen mehr waere, sondern Absicht und gegebenenfalls
> Bloedheit...

Wenn du wüstest, was ich schon alles an "unabsichtlichen casts" gesehen 
habe. Da gibt der Compiler eine Fehlermeldung, dass der Datentyp nicht 
passt. Schreibt noch dazu, welcher Datentyp eigentlich erwartet wird und 
schon steht ein entsprechender Cast dort.

Gut: fällt alles in die Kategorie 'Blödheit'. Nichts desto trotz würde 
man sich gegen so manchen Cast als Programmierer gerne schützen können 
:-)

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes:
hab ich dann auch ziemlich schnell gemerkt ;)

Genau so wie Karl Heinz es vorschlägt wollte ich es haben!
Das man wenn man unbedingt will da was flasches casten kann ist nicht so 
schlimm, da ist man dann selber schuld!

Allerdings funktioniert das bei mir noch nicht so ganz...
ich habe einen enum:
enum WaveForms { dds_WF_Sin=0x00, dds_WF_Tri=0x02, dds_WF_Rect=0x28 };

und einen Prototypen in der datei dds.h
void dds_SetWaveForm(enum WaveForms WaveForm);
in der dds.c steht dann
void dds_SetWaveForm(enum WaveForms WaveForm){
  send16 s;
  s.i16=0;
  if (dds_Stat.FSel) s.i16|=dds_CRB_FSELECT;
  if (dds_Stat.PSel) s.i16|=dds_CRB_PSELECT;
  s.i16|=(dds_CRB_B28|WaveForm);
  dds_Stat.WvFrm=WaveForm;
  dds_CS_En();
  spi_Write(s.i8h);    //Send Hi Byte
  spi_Write(s.i8l);    //Send Lo Byte
  dds_CS_Dis();
}

In der main include ich die dds.h und rufe folgendes auf:
dds_SetWaveForm(5);

Das gibt allerdings leider KEINEN Compilerfehler :(
Was mache ich falsch?
Funktionieren an sich tut das Prog nur bekomme ich halt keinen Fehler..

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weil der Compiler einen enum-Typ als Integerwert annimmt also kann jeder 
Wert gültig sein! Überprüfen ob er gültig ist bei Werten musst du es so 
machen wie ich es beschrieben habe!

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Egal ob Casten oda nicht in C ist und bleibt es ein Integerwert!!

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Dirk,

mit fällt da nur so seltsame Sachen ein wie per typedef ein struct 
"waveform" zu definieren, das nur ein uint8_t-Element enthält, und 
entsprechende konstante Variablen damit zu definieren.
typedef struct{uint8_t wert;} waveform;

const waveform dds_WF_Sin = {0x00};
const waveform dds_WF_Tri = {0x02};
const waveform dds_WF_Rect = {0x28};
Schön ist das aber nicht.

Wäre es nicht wirklich besser, die Nutzer auf die Verwendung der 
#define-Konstanten zu verpflichten und zur Sicherheit einen Test zur 
Laufzeit auf gültige Werte zu nutzen?

Gruß, DetlevT

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:

> In der main include ich die dds.h und rufe folgendes auf:
>
> dds_SetWaveForm(5);
> 
>
> Das gibt allerdings leider KEINEN Compilerfehler :(

Shit.
Habs extra noch ausprobiert. Hab aber übersehen, dass mein Compiler als 
C++ Compiler arbeitet.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Shit.
> Habs extra noch ausprobiert. Hab aber übersehen, dass mein Compiler als
> C++ Compiler arbeitet.

Einer der vielen guten Gruende, auch C mit dem C++-Compiler zu 
entwickeln ;-)

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
grml grml
Hmm naja gut kann man nichts machen. Ursprünglich habe ich  mal Pascal 
gelernt da wäre das sicherlich gegangen.. Naja C halt..

Wie dem auch sei, EUCH allen trotzdem ganz vielen Dank!

Grüße
Dirk H.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorsicht übrigens noch mit der 'enum' -- die braucht beim AVR-GCC gerne 
mal einen ganzen Integer, was meistens Speicherverschwendung ist :-)

Aber mal ehrlich: Wenn du nicht gerade ein weltbewegendes API 
programmierst, sollte man doch in der Lage sein, die paar Aufrufe 
korrekt hinzuschreiben :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.