eigener Variablentyp

Gast #1205926
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
#1205943
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.
Gast #1205960
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.
Gast #1206007
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...
Gast #1206011
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...
#1206012
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.
#1206019
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 
:-)
Gast #1206049
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..
#1206082
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren