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
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.
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...
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.
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...
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...
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.
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 :-)
@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..
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!
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
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.
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 ;-)
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.