Je veux exécuter un autre programme dans le code C. Par exemple, je veux exécuter une commande
./foo 1 2 3
foo
est le programme qui existe dans le même dossier, et 1 2 3
sont des arguments. Le programme foo
crée un fichier qui sera utilisé dans mon code.
Comment puis-je faire cela?
Pour un moyen simple, utilisez system()
:
#include <stdlib.h>
...
int status = system("./foo 1 2 3");
system()
attendra que foo termine son exécution, puis renverra une variable d'état que vous pourrez utiliser pour vérifier, par exemple, par exemple. exitcode (le code de sortie de la commande est multiplié par 256, divisez donc la valeur renvoyée par system () par celle-ci pour obtenir le code de sortie réel: int exitcode = status / 256
).
La page de manuel de wait()
(dans la section 2, man 2 wait
Sur votre système Linux) répertorie les différentes macros que vous pouvez utiliser pour examiner le statut, les plus intéressantes être WIFEXITED
et WEXITSTATUS
.
Sinon, si vous avez besoin de lire la sortie standard de foo, utilisez popen(3)
, qui renvoie un pointeur de fichier (FILE *
); interagir avec les entrées/sorties standard de la commande revient alors à lire ou à écrire dans un fichier.
La fonction system
appelle un shell pour exécuter la commande. Bien que cela soit pratique, il est bien connu implications pour la sécurité . Si vous pouvez spécifier le chemin du programme ou du script à exécuter et perdre l’indépendance de la plate-forme fournie par system
, vous pouvez utiliser un wrapper execve
comme illustré dans le exec_prog
fonction ci-dessous pour exécuter votre programme de manière plus sécurisée.
Voici comment vous spécifiez les arguments dans l'appelant:
const char *my_argv[64] = {"/foo/bar/baz" , "-foo" , "-bar" , NULL};
Puis appelez le exec_prog
fonctionne comme ceci:
int rc = exec_prog(my_argv);
Ici se trouve le exec_prog
une fonction:
static int exec_prog(const char **argv)
{
pid_t my_pid;
int status, timeout /* unused ifdef WAIT_FOR_COMPLETION */;
if (0 == (my_pid = fork())) {
if (-1 == execve(argv[0], (char **)argv , NULL)) {
perror("child process execve failed [%m]");
return -1;
}
}
#ifdef WAIT_FOR_COMPLETION
timeout = 1000;
while (0 == waitpid(my_pid , &status , WNOHANG)) {
if ( --timeout < 0 ) {
perror("timeout");
return -1;
}
sleep(1);
}
printf("%s WEXITSTATUS %d WIFEXITED %d [status %d]\n",
argv[0], WEXITSTATUS(status), WIFEXITED(status), status);
if (1 != WIFEXITED(status) || 0 != WEXITSTATUS(status)) {
perror("%s failed, halt system");
return -1;
}
#endif
return 0;
}
Rappelez-vous le comprend:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
Voir publication SE liée pour les situations nécessitant une communication avec le programme exécuté via des descripteurs de fichier tels que stdin
et stdout
.
Vous pouvez utiliser fork()
et system()
pour que votre programme ne soit pas obligé d'attendre le retour de system()
.
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[]){
int status;
// By calling fork(), a child process will be created as a exact duplicate of the calling process.
// Search for fork() (maybe "man fork" on Linux) for more information.
if(fork() == 0){
// Child process will return 0 from fork()
printf("I'm the child process.\n");
status = system("my_app");
exit(0);
}else{
// Parent process will return a non-zero value from fork()
printf("I'm the parent.\n");
}
printf("This is my main program and it will continue running and doing anything i want to...\n");
return 0;
}
En C
#include <stdlib.h>
system("./foo 1 2 3");
En C++
#include <cstdlib>
std::system("./foo 1 2 3");
Ensuite, ouvrez et lisez le fichier comme d'habitude.
system()
exécute un shell qui est ensuite responsable de l'analyse des arguments et de l'exécution du programme souhaité. Pour exécuter le programme directement, utilisez fork () et exec () (ce que system () utilise pour exécuter le shell ainsi que ce que le shell utilise pour exécuter des commandes).
#include <unistd.h>
int main() {
if (fork() == 0) {
/*
* fork() returns 0 to the child process
* and the child's PID to the parent.
*/
execl("/path/to/foo", "foo", "arg1", "arg2", "arg3", 0);
/*
* We woundn't still be here if execl() was successful,
* so a non-zero exit value is appropriate.
*/
return 1;
}
return 0;
}
Que diriez-vous comme ça:
char* cmd = "./foo 1 2 3";
system(cmd);
Voici le moyen d'étendre aux arguments variables les arguments qui ne sont pas codés en dur (bien qu'ils soient encore codés en dur dans cet exemple, mais il devrait être facile de comprendre comment étendre ...):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int argcount = 3;
const char* args[] = {"1", "2", "3"};
const char* binary_name = "mybinaryname";
char myoutput_array[5000];
sprintf(myoutput_array, "%s", binary_name);
for(int i = 0; i < argcount; ++i)
{
strcat(myoutput_array, " ");
strcat(myoutput_array, args[i]);
}
system(myoutput_array);