C/C++でexecvp()関数を使用する方法はどうですか。
この記事では、C / C++でexecvp()関数を使用する方法について見ていきます。
UNIXにおいて、Cプログラムを使用して別のプログラムを実行したい場合は、execvp()関数が非常に便利です。
注意:この機能はUNIXベースのオペレーティングシステムにのみ適用されます。Windowsでは機能しません。
私たちのプログラムからUNIXコマンドを実行する方法について、具体的な例を使って見てみましょう!
execvp()の基本的な構文
この関数は、実行するUNIXコマンドの名前を最初の引数として受け取ります。
この部分は「unistd.h」ヘッダーファイルに含まれているため、プログラムに含める必要があります。
#include <unistd.h>
int execvp(const char* command, char* argv[]);
ここでは、「コマンド」とは、PATH環境変数の一部である任意のバイナリ実行可能ファイルを指します。したがって、カスタムプログラムを実行したい場合は、必ずそれをPATH変数に追加してください!
第二引数のargvは、コマンドへの引数のリストを表します。これはchar*の文字列の配列です。
ここでは、argvにはコマンドとその引数が含まれています。
たとえば、下記の配列はargvの形式に従っています。
char* argument_list[] = {"ls", "-l", NULL}; // NULL terminated array of char* strings
// Ok! Will execute the command "ls -l"
execvp("ls", argument_list);
この配列は必ずNULLで終了しなければなりません。つまり、argvの最後の要素はNULLポインタでなければなりません。
私たちのCプログラムは今どうなりますか? (Watashitachi no C puroguramu wa ima dou narimasu ka?)
この機能は、現在のプロセス(Cプログラム)の制御をコマンドに委譲します。そのため、Cプログラムは即座に実際のコマンドで置き換えられます。
したがって、execvp()の後に来るものは、私たちのプログラムが完全に接収されるため、実行されません!
しかし、何らかの理由でコマンドが失敗した場合、execvp()は-1を返します。
したがって、execvp()を使用する場合は、Cプログラムを維持するために通常、fork()を使用して最初に新しいプロセスを生成し、その新しいプロセス上でexecvp()を使用します。
これは「フォークとエグゼク」と呼ばれるモデルであり、C言語を使用して複数のプロセスを実行する際の標準的な方法です。
さあ、いくつかの例を見て、この関数をよりよく理解しましょう。また、Cプログラムを持ちながら、fork()とexecvp()を使用することもあります!
C / C++でexecvp()を使用する方法とその例 – いくつかの例
もし、fork()を使わずに新しいプロセスを生成せずにexecvp()を使用した場合に起こる具体的な動作を確認したいのであれば、以下のプログラムがそれを示しています。
私たちはCプログラムから「ls -l」を実行します。
execvp()の後のprintf()ステートメントは実行されないことに注意してください。なぜなら、他のプロセスが制御を取っているからです。
#include <stdio.h>
#include <unistd.h>
int main() {
char* command = "ls";
char* argument_list[] = {"ls", "-l", NULL};
printf("Before calling execvp()\n");
// Calling the execvp() system call
int status_code = execvp(command, argument_list);
if (status_code == -1) {
printf("Process did not terminate correctly\n");
exit(1);
}
printf("This line will not be printed if execvp() runs correctly\n");
return 0;
}
出力
Before calling execvp()
total 3
-rwxrwxrwx 1 user user 22088 May 30 16:37 a.out
-rwxrwxrwx 1 user user 16760 May 30 16:37 sample
-rw-rw-rw- 1 user user 1020 May 30 16:37 sample.c
ご覧の通り、execvp()の後の部分はまったく実行されません。なぜなら、”ls -l”がプロセスを制御しているからです!
同じ例を書き換えてみましょうが、fork()を使用してexecvp() システムコールを別のプロセスで実行するようにしましょう。
今、何が起こるか見てみましょう。
#include <stdio.h>
#include <unistd.h>
int main() {
char* command = "ls";
char* argument_list[] = {"ls", "-l", NULL};
printf("Before calling execvp()\n");
printf("Creating another process using fork()...\n");
if (fork() == 0) {
// Newly spawned child Process. This will be taken over by "ls -l"
int status_code = execvp(command, argument_list);
printf("ls -l has taken control of this child process. This won't execute unless it terminates abnormally!\n");
if (status_code == -1) {
printf("Terminated Incorrectly\n");
return 1;
}
}
else {
// Old Parent process. The C program will come here
printf("This line will be printed\n");
}
return 0;
}
出力
Before calling execvp()
Creating another process using fork()...
This line will be printed
user@shell:$ total 3
-rwxrwxrwx 1 user user 22088 May 30 16:37 a.out
-rwxrwxrwx 1 user user 16760 May 30 16:37 sample
-rw-rw-rw- 1 user user 1020 May 30 16:37 sample.c
もしシェル上であれば、出力が奇妙に見えるかもしれませんが、それは複数のプロセスが並行して実行されたためです!両方の出力が確かに印刷されたため、私たちは問題を解決することができました。
結論
C/C++上でexecvp()関数の使い方を学びました。これは、Cプログラムから他のプログラムを実行するためのものです。ただし、注意点として、これにより他のプログラムが私たちのプロセスを完全に制御できることになります。
このため、私たちはfork()システムコールを使用して、これを別のプロセスの下に閉じ込める必要があります。おそらく、これはあなたには理解できて、他のプログラムを実行しながらもCプログラムを制御できるようになります!
参考文献を日本語で自然に言い換えてください。
- Linux manual page on the execvp() function in C