Forum: Compiler & IDEs eigener Variablentyp


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Dirk (Gast)


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

von Karl H. (kbuchegg)


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
1
enum WaveForms { dds_WF_Sin, dds_WF_Tri, dds_WF_Rect };
2
3
void dds_SetWaveForm( enum WaveForms form );
4
5
int main()
6
{
7
  SetWaveForm( dds_WF_Sin );
8
}

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

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

von Johannes M. (johnny-m)


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...

von Daniel (Gast)


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.

von P. S. (Gast)


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...

von P. S. (Gast)


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...

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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 
:-)

von Dirk (Gast)


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:
1
enum WaveForms { dds_WF_Sin=0x00, dds_WF_Tri=0x02, dds_WF_Rect=0x28 };

und einen Prototypen in der datei dds.h
1
void dds_SetWaveForm(enum WaveForms WaveForm);
in der dds.c steht dann
1
void dds_SetWaveForm(enum WaveForms WaveForm){
2
  send16 s;
3
  s.i16=0;
4
  if (dds_Stat.FSel) s.i16|=dds_CRB_FSELECT;
5
  if (dds_Stat.PSel) s.i16|=dds_CRB_PSELECT;
6
  s.i16|=(dds_CRB_B28|WaveForm);
7
  dds_Stat.WvFrm=WaveForm;
8
  dds_CS_En();
9
  spi_Write(s.i8h);    //Send Hi Byte
10
  spi_Write(s.i8l);    //Send Lo Byte
11
  dds_CS_Dis();
12
}

In der main include ich die dds.h und rufe folgendes auf:
1
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..

von Daniel (Gast)


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!

von Daniel (Gast)


Lesenswert?

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

von Detlev T. (detlevt)


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.
1
typedef struct{uint8_t wert;} waveform;
2
3
const waveform dds_WF_Sin = {0x00};
4
const waveform dds_WF_Tri = {0x02};
5
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

von Karl H. (kbuchegg)


Lesenswert?

Dirk wrote:

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

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

von P. S. (Gast)


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 ;-)

von Dirk (Gast)


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.

von Sven P. (Gast)


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 :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.