www.mikrocontroller.net

Forum: PC-Programmierung Switch case mit string


Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe c++ porgramm entwickelt, dass ich jetzt mit Hilfe von 
Parametern aus der Console aus aufrufen möchte.

also z.B.: "myprog.exe -reset"
Dann soll der reset ausgeführt werden und vieles mehr.
Da es hier mindestens 15 fälle gibt wollte ich das mit einer Switch case 
realisieren, dass will aber nicht funktionieren.

Hat jmd. eine sinnvolle Idee, wie ich das realisieren kann. Switch case 
kann nur char oder int. Also habe ich versucht das zu mappen, aber das 
hat nicht richtig funktioniert.

Des weiteren bin ich auch getopt gestoßen, aber das bekomme ich iwie 
nicht richtig zum laufen (windows).

Hat jmd. eine Idee? Hat jmd. schonmal ein ähnliches problem gehabt?

Ich hab also mehrere Anstäze und keiner hat auf Anhieb funktionier ;) 
Jetzt wollte ich mich erstmal umhören, bevor ich mich auf einen 
festlege.

Vielen dank für die Ideen schonmal.

Grüße tom

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

Bewertung
0 lesenswert
nicht lesenswert
Tom A. schrieb:

> Hat jmd. eine sinnvolle Idee, wie ich das realisieren kann.

  if( ...... ) {
  }

  else if( ...... ) {
  }


  else if( ...... ) {
  }

  else {
  }

Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau darum habe ich nach einer sinnvollen Idee gefragt ;)
Stell dir das jetzt 15 mal vor... Das ist nicht sonderlich schön ^^

Bin für weitere Ideen noch offen :D

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann gib uns bitte mehr Informationen.
Was ist eine "schöne" Löaung, eine "sinnvolle"?
Das sind abstrakte Eigenschaften die jeder anders objektiviert.

Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es kann ja nicht sein, dass ich 15 IF abfragen hintereinander machen 
muss oder liege ich da falsch?

Bei fast bei jedem Befehl in der cmd gibt es die Parameter, welche 
einfach angehängt werden. Ich dachte eben, dafür gibt es eine Art 
Standard wie das im allgemeinen gelöst wird.

Würdet ihr das etwa mit IF-ELSE lösen?

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach dir ein Array, wo du alle "Vergleichsstrings" ablegst und mach vor 
dem Switch ein strcmp und werte die Zahl aus. Also etwa so
#include <stdlib.h>
#include <stdio.h>

#define NR_STRINGS 5
char cmp_strings[][20] = {"scheisse","mit","erdbeeren","ihh", "erdbeeren!"};

int main(){
   int cmp_str,i;
   char buffer[]="mit";
   
   //string_abfragen(buffer);
   
   for(i=0; i < NR_STRINGS; i++){
     if(!strcmp(buffer, cmp_strings[i]))
       break;
     if(i == NR_STRINGS -1)
       i = -1;
   }
   switch(i){
      case 0:
        printf("Da stand was ekeliges drin");
        break;
      case 1:
        printf("Da stand \"mit\" drin");
        break;
      ...
   }
}

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde getopt nehmen.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom A. schrieb:
> Es kann ja nicht sein, dass ich 15 IF abfragen hintereinander machen
> muss oder liege ich da falsch?

was glaubst du denn wie ein switch case funktioniert? (Es wird nich 
immer mit Sprungtabelle gearbeitet!)

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geht natürlich auch so:
#include <stdlib.h>
#include <stdio.h>

#define NR_STRINGS 5
char *cmp_strings[] = {"scheisse","mit","erdbeeren","ihh", "erdbeeren!"};

int main(){
   int cmp_str,i;
   char buffer[20];
   
   string_abfragen(buffer);
   
   for(i=0; i < NR_STRINGS; i++){
     if(!strcmp(buffer, cmp_strings[i]))
       break;
     if(i == NR_STRINGS -1)
       i = -1;
   }
   switch(i){
      case 0:
        printf("Da stand was ekeliges drin");
        break;
      case 1:
        printf("Da stand \"mit\" drin");
        break;
      ...
   }
}

Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
mit den Posts hat es sich gerade ein wenig überschlagen. Ich hab mich 
jetzt für die Lösung von Timmo entschieden, die ist meiner Meinung nach 
sehr elegant ;)
Hab noch kurz eine schleife drumherum gebaut und ZACK kann man alle 
Eingabeparameter auswerten.

Vielen Dank nochmal, an alle die sich hier so schnell und fleißig 
gemeldet haben.

Hier das Resultat:
#define NR_STRINGS 5
char *cmp_strings[20] = {"-status","-reset","erdbeeren","ihh", "erdbeeren!"};


int main(int argc, char** argv)
{
  USBDev a;

   int cmp_str,i;
   for(int j =1;j<argc;j++)
   {  
     for(i=0; i < NR_STRINGS; i++){
     if(!strcmp(argv[j], cmp_strings[i]))
       break;
     if(i == NR_STRINGS -1)
       i = -1;
     }
       switch(i){
        case 0:
        printf("-status");
        break;
        case 1:
        printf("-reset");
        break;
       }
   }
}

Autor: Vorschlag (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde eine Klasse dazu erstellen. Für jeden Parameter instanzierst 
du diese Klasse und übergibst ihr die Kommandozeile und den Parameter 
den du haben willst. Nun baust du noch eine Funktion ein die prüft ob 
der Parameter gesetzt wurde, dieser gibt halt true oder false zurück, je 
nachdem ob der Parameter in der übergebenen Liste ist oder nicht.

z.b. hab ich eine Klasse generiert die "clpar" heisst.
Als Konstruktor nimmt sie argc, argv und den Parameter (in echt noch 
mehr).
Dann gibts noch ne Funktion namens isSet() (auch hier natürlich noch 
andere).

Also z.B.:
clpar parameterABC(argc, argv, "--ABC");
clpar parameterDEF(argc, argv, "-def");

if (parameterABC.isSet()) // hier tue was

Das war jetzt natürlich nur so grob die Vorgehensweise.
Damit hat man ne schöne Kapselung vom Rest des Projektes und kann die 
Klasse immer schön wiederverwenden.
Ich hab z.B. noch so Sachen wie Argumente für Parameter und deren 
Prüfung mittels Regex eingebaut.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mich nach getopt umschauen. Oder die Parameter sortieren und 
mit bsearch() arbeiten.

Alternativ kann man in der Suchtabelle prima Callbacks hinterlegen oder 
Zeiger auf Flaggen und so weiter.

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oder xgetopt

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde sogar sagen, man könnte getopt nehmen.

Autor: nicht Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom A. schrieb:
> Ich hab mich
> jetzt für die Lösung von Timmo entschieden, die ist meiner Meinung nach
> sehr elegant ;)

Dann mach es so, ich finde es nicht sehr schön, da man ein 
aussagekräftigen string Vergleich durch eine Zahl ersetzt wird.
Ein paar else if Anweisungen finde ich persönlich schöner, die muss man 
dann noch nicht mal mehr kommentieren, da der Inhalt schon der Kommentar 
ist.

und wie schon gesagt bist du nicht der erste der das Problem hatte -> 
getopt

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was in C++ auch geht, ist eine
  std::map< std::string, void(*)() >   meinemap;
oder so ähnlich, also eine Map, die Strings auf Funktionen mappt.
Dann geht die Auswahl mit einem schnöden meinemap[meinstring]()
oder ggf. analog mit Parametern oder Funktionsobjekten statt
Funktionen, falls man richtig schick programmieren will.

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

Bewertung
0 lesenswert
nicht lesenswert
Tom A. schrieb:

> Würdet ihr das etwa mit IF-ELSE lösen?

Kommt drauf an.
Wenn das alles ist, was ausgewertet werden muss: Ja, warum nicht?
15 sind doch nicht viel.

Das ist einfach, schnell geschrieben, leicht zu durchschauen, leicht zu 
erweitern (im Falle eines Falles).

Der Lösung krampfhaft einen switch-case über den Umweg eines Indizes 
einzuführen, kann ich zb überhaupt nichts abgewinnen. Da ist die 
eigentlich wichtige Information, nämlich welches Codestück zu welchem 
Paramater gehört über einen nicht unerkleckliches Stück Code 
verschmiert. Um zu wissen, wann genau der case mit der Nummer 13 
ausgeführt wird, muss ich Wörter in einem Array abzählen. Da schau ich 
lieber auf das if am Anfang des Abschnitts, denn dort steht im Klartext, 
wie die Option lautet. Denn: kürzer ist diese 'Index in Array suchen und 
darauf ausbauen switchen' Lösung in Wirklichkeit auch nicht. Sie 
verschleiert nur ein wenig mehr, was da eigentlich passiert.

Aber seis drum.
Irgendwann wirst auch du merken, dass die vermeintliche Tipparbeit das 
kleinste aller Probleme ist. Code schreibt man nur einmal (ok, manchmal 
wird er noch korrigiert), aber man liest ihn viele male. Da schreib ich 
mir den Code lieber so, dass ich beim Lesen nicht vielen Querverweisen 
folgen und ständig rauf/runter scrollen muss um die Details zu sehen.

Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, das mit der switch case, das sehe ich nun auch ein ist Käse ;) da 
man später wirklich nicht mehr durch ...

Ich werde mir jetzt mal das mappen von Funktionen anschauen und mal 
schauen ob das eine gute Lösung für mich ist.

Die if else Lösung finde ich nach wie vor noch nicht soooo tolle ;)

Danke für die Ideen.

Grüße Tom

Autor: Tom A. (thomas_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, also ich werde es jetzt mal mit einer map realisieren, wenn mich 
dann nochmal etwas stören sollte, werde ich es über den haufen werfen ;)

Die Lösung sieht jetzt so aus:
#include <iostream>
#include <string>
#include <map>
using namespace std;


void status() { cout << "status" << endl; }
void reset() { cout << "reset" << endl; }

int main(int argc, char** argv)
{


  typedef void (*ptr_fct)();
  typedef   map<string, ptr_fct> MapCall;
  MapCall fct_map;
  fct_map.insert(MapCall::value_type("-status",status));
  fct_map.insert(MapCall::value_type("-reset",reset));
  MapCall::const_iterator call;

  
  for(int i =1; i<argc;i++)
  {
    call = fct_map.find(argv[i]);
    if (call != fct_map.end())
    {
      (*call).second();
    }
    else
      cout << "Unknown call requested" << endl;
  }
}

Vielen dank für die Inspiration ;)

Grüße Tom

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom A. schrieb:
> Die if else Lösung finde ich nach wie vor noch nicht soooo tolle
Macht auch nicht das was du jetzt programmiert hast, den auf diese Weise 
werden alle Übergebenen Befehle ausgewertet, bei der else/if Lösung 
jedoch höchstens einer...

Autor: Rolf Magnus (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Was in C++ auch geht, ist eine
>   std::map< std::string, void(*)() >   meinemap;
> oder so ähnlich, also eine Map, die Strings auf Funktionen mappt.
> Dann geht die Auswahl mit einem schnöden meinemap[meinstring]()

Nein, denn das hätte böse Folgen, wenn jemand einen Paramter übergibt, 
den das Programm nicht kennt. Tom hat das mit der Benutzung von find() 
schon richtig gemacht.

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.