/ Sonstiges: Programm aus C++ aufrufen
noname
- programmiertechnik
1 *Markus1 Christian Seiler0 noname
Hallo SelfForum.
Es gibt ja verschiedene Möglichkeiten, aus einem C/C++ Programm heraus ein anderes Programm aufzurufen, etwa:
system("/bin/ls");
oder
execl("/bin/ls", "ls", "-l", NULL);
oder
spawnl(P_WAIT, "/bin/ls", "-l", NULL);
Manchmal mit Rückgabewert, manchmal ohne. Zur Frage:
Gibt es noch weitere Funktionen? Welche würdet ihr verwenden? Wie sähe eine saubere Lösung aus?
Mir ist es wichtig, einen Rückgabewert zu haben, nach dem ich weiter handeln kann.
Gruß und Dank,
noname
Hallo,
es kommt ganz darauf an, wie sich das Programm verhalten soll. Wie soll der Childprozess verarbeitet werden? Gibt es eine fixe Anzahl an Argumenten oder nicht. Auf welchem OS soll das Programm laufen (spawn ist kein Posix-Standard).
Bei spawn gibt es AFAIK schon mal zumindest diese Möglichkeiten.
int spawnl(int mode, char *path, char *arg0, arg1, ..., argn, NULL);
int _wspawnl(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL);
int spawnle(int mode, char *path, char *arg0, arg1, ..., argn, NULL, char *envp[]);
int _wspawnle(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL, wchar_t *envp[]);
int spawnlp(int mode, char *path, char *arg0, arg1, ..., argn, NULL);
int _wspawnlp(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL);
int spawnlpe(int mode, char *path, char *arg0, arg1, ..., argn, NULL, char *envp[]);
int _wspawnlpe(int mode, wchar_t *path, wchar_t *arg0, arg1, ..., argn, NULL, wchar_t *envp[]);
int spawnv(int mode, char *path, char *argv[]);
int _wspawnv(int mode, wchar_t *path, wchar_t *argv[]);
int spawnve(int mode, char *path, char *argv[], char *envp[]);
int _wspawnve(int mode, wchar_t *path, wchar_t *argv[], wchar_t *envp[]);
int spawnvp(int mode, char *path, char *argv[]);
int _wspawnvp(int mode, wchar_t *path, wchar_t *argv[]);
int spawnvpe(int mode, char *path, char *argv[], char *envp[]);
int _wspawnvpe(int mode, wchar_t *path, wchar_t *argv[], wchar_t *envp[]);
Markus
Hallo.
Danke dir für die ausführliche Antwort.
Wie soll der Childprozess verarbeitet werden?
Was meinst du genau?
Das Programm soll erstmal auf Linux laufen, gerne aber auch auf Win und MacOS. spawn fällt dann wohl schon raus. exec kehrt nur im Fehlerfall zum ausführenden Programm zurück, für mich daher auch nicht wirklich zu gebrauchen. Alternativen zu den drei oben genannten Funktionen?
Hi,
Bei spawn gibt es AFAIK schon mal zumindest diese Möglichkeiten. [...]
Lauter ähnliche Funktionen aufzuführen, ohne den Unterschied zu erklären, halte ich für wenig sinnvoll. Daher mal eine Erklärung (gilt analog zu exec*(), die Suffixe sind dieselben):
* Präfix:
(keines) Akzeptiert (char *) als Parameter und damit Strings in
der aktuellen 8bit-Kodierung des Systems
_w Akzeptiert (wchar_t *) als Parameter und damit Strings
in UTF-16/UCS-2 bzw. dem gewurschtel, was der C-Standard
traurigerweise mit wchar_t angestellt hat.
* Suffix:
- Parameterübergabe:
l Übergib die Argumente als variable Parameterzahl, nach
dem letzten Argument folgt NULL als weiterer Parameter, um
die Liste abzuschließen. »l« steht für »list«
v Übergib die Argumente als Array, das letzte Argument im
Array wird von NULL gefolgt, um das Ende zu markieren.
»v« steht für »vector«.
Beachte: Das "nullte" Argument muss trotzdem immer noch der
Programmname sein, auch wenn man den irgendwie schon einmal vorher
übergeben hat (als Parameter unmittelbar vor der Argumentliste).
- Umgebungsvariablen:
(nichts) Vererbe die Umgebungsvariablen des eigenen Prozesses.
e Übergib eigene Umgebungsvariablen als Array von
Strings, ein NULL kennzeichnet das Ende des Arrays.
»e« steht für »environment«. Die Strings haben den
Inhalt "VARIABLE=wert", Format ist identisch zum
globalen environ-Array bzw. zum optional dritten
Parameter der main()-Funktion.
- Suchpfad
(nichts) Erwarte für den Pfad-Parameter einen relativen oder
absoluten Pfad.
p Wenn der Pfad-Parameter kein expliziter Pfad ist,
d.h. keinen Pfadtrenner (/ unter POSIX, \ unter
Windows) enthält, dann suche im Suchpfad danach, d.h.
in der Umgebungsvariable PATH oder in deren Default-
wert, sofern die nicht vorhanden ist.
Beispiele für letzten Punkt:
spawnlp(_P_WAIT, "notepad", "notepad", "C:\\test.txt", NULL);
-> funktioniert, findet notepad
spawnl(_P_WAIT, "notepad", "notepad", "C:\\test.txt", NULL);
-> funktioniert nicht, da eine Datei "notepad" im aktuellen
Verzeichnis nicht existiert
~~~c
spawnlp(_P_WAIT, "C:\Windows\notepad.exe", "notepad", "C:\test.txt", NULL);
spawnl(_P_WAIT, "C:\Windows\notepad.exe", "notepad", "C:\test.txt", NULL);
-> kein Unterschied
Beispiel für die v-Funktionen:
~~~c
char *args[] = {
"notepad",
"C:\\test.txt",
NULL
};
spawnv(_P_WAIT, "C:\\Windows\\notepad.exe", args);
Beispiele für die e-Funktionen:
char *args[] = {
"notepad",
"C:\\test.txt",
NULL
};
char *env[] = {
"FOO=bar",
"BAZ=blub",
NULL
};
spawnve(_P_WAIT, "C:\\Windows\\notepad.exe", args, env);
Viele Grüße,
Christian
Hallo,
system("/bin/ls");
system() ist ANSI C und ruft den Befehl mit Hilfe der System-Shell auf. Die Dateideskriptoren werden vererbt (d.h. Standardausgabe des aufgerufenen Programms ist die eigene Standardausgabe etc.), es wird gewartet, bis der Befehl vollständig ausgeführt wird. Der Befehl wird in einem separaten Prozess ausgeführt.
execl("/bin/ls", "ls", "-l", NULL);
Das ist unter POSIX (also Linux, Solaris, *BSD, Mac OS X, ...) sowie unter Windows verfügbar - die exec*-Funktionen ersetzen (!) den Inhalt des aktuellen Prozesses mit dem des neuen Prozesses, d.h. nach einem erfolgreichen exec* wurde der eigene Prozess komplett übernommen, d.h. es wird danach kein Code mehr ausgeführt.
spawnl(P_WAIT, "/bin/ls", "-l", NULL);
Das ist nur unter Windows verfügbar und erzeugt einen separaten Prozess (/bin/ls gibt's unter Windows nicht, d.h. Dein Beispiel würde nicht funktionieren), der je nach Flag im ersten Parameter synchron (es wird gewartet, bis der Prozess sich beendet hat) oder asynchron (die Kontrolle wird sofort zurückgegeben) ausgeführt wird.
Manchmal mit Rückgabewert, manchmal ohne. Zur Frage:
Gibt es noch weitere Funktionen?
Unter Windows gibt's noch CreateProcess() (direkter Kernelaufruf) und ShellExec() oder ShellExecute() (in shell32.dll, schlag nach, welche von beiden Varianten die richtige ist, ich hab's vergessen). Unter POSIX gibt's noch die Möglichkeit, per Kombination aus fork() + exec() + waitpid() Prozesse auszuführen, die den aktuellen Prozess *nicht* ersetzen. (so funktioniert system() intern auf POSIX-Betriebssystemen)
Welche würdet ihr verwenden? Wie sähe eine saubere Lösung aus?
Wenn Du möglichst portabel arbeiten willst, dann empfehle ich Dir system(), sofern Dir die Funktionalität und die Kontrolle ausreicht. Das nimmt Dir eine Menge arbeit ab, ist auf allen relevanten Betreibssystemen vorhanden (die auszuführenden Befehle sind nur anders) und gibt Dir den Rückgabewert auch direkt zurück.
Ansonsten wäre unter Windows vmtl. spwan* die Variante Deiner Wahl, während Du Dir unter POSIX-Betriebssystemen wohl eine eigene fork() + exec*() + waitpid() Lösung bauen willst, um (wie Du es vorhast), den Rückgabewert zu erhalten.
Beachte eines noch: Unter POSIX-Betriebssystemen solltest Du system() *nicht* einsetzen, wenn Du Programme schreibst, die setuid-root sind. Dann empfiehlt sich wirklich ein eigener fork() + exec() + waitpid()-Ansatz.
Wenn Du etwas näher beschreiben würdest, was für ein Programm Du in welchem Zusammenhang ausführen willst, kann man Dir vielleicht auch eine spezifische Empfehlug für die eine oder andere Methode geben.
Viele Grüße,
Christian
Lieben Dank für deine Ausführung. Ich versuche noch vor Archivierung des Threads nochmal darauf zurück zu kommen..