由于execvp() 仅适用于以空字符结尾的字符串,因此您要么必须以空字符结尾的字符串,要么……实际上,没有 or 选项,因为所有系统调用都使用空字符终止的字符串。
好的:另一种方法是制作以 null 结尾的字符串副本并使用副本调用 execvp()。由于您知道它们有多长,因此您将能够相当有效地执行此操作 - 但您需要分配足够的内存。
size_t req_size = 0;
for (int i = 0; i < n; i++)
req_size += (com->tokens[i][1] - com->tokens[i][0] + 2);
char **argv = malloc((n + 1) * sizeof(argv[0]));
char *args = malloc(req_size);
if (argv == 0 || args == 0)
…report memory allocation failure; do not continue…
char *argp = args;
int i;
for (i = 0; i < n; i++)
{
size_t len_i = com->tokens[i][1] - com->tokens[i][0] + 1;
argv[i] = argp;
memmove(argv[i], com->tokens[i][0], len_i);
argv[i][len_i] = '\0';
argp += len_i + 1;
}
assert(argp == args + req_size);
argv[i] = 0; // Null terminate list of pointers
execvp(argv[0], argv);
嵌入 SSCCE 的代码 (Short, Self-Contained, Correct Example):
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct command
{
int n;
char *tokens[50][2];
};
static void print_fixed(struct command *com)
{
printf("fixed:\n");
printf("%d:", com->n);
for (int i = 0; i < com->n; i++)
printf(" [%.*s]", (int)(com->tokens[i][1] - com->tokens[i][0] + 1), com->tokens[i][0]);
putchar('\n');
}
static void print_argv(int argc, char **argv)
{
printf("argv:\n");
for (int i = 0; i <= argc; i++)
{
char *arg = argv[i];
if (arg == 0)
arg = "<<NULL pointer>>";
printf("%d: [%s]\n", i, arg);
}
}
int main(void)
{
char data[] = "command arg1 arg2 arg3 arg4";
struct command cmd =
{
5,
{ { &data[ 0], &data[ 6] }, { &data[ 8], &data[11] },
{ &data[13], &data[16] }, { &data[18], &data[21] },
{ &data[23], &data[26] },
}
};
struct command *com = &cmd;
int n = com->n;
print_fixed(com);
size_t req_size = 0;
for (int i = 0; i < n; i++)
req_size += (com->tokens[i][1] - com->tokens[i][0] + 2);
char **argv = malloc((n + 1) * sizeof(argv[0]));
char *args = malloc(req_size);
if (argv == 0 || args == 0)
{
fprintf(stderr, "Memory allocation failure\n");
exit(1);
}
char *argp = args;
int i;
for (i = 0; i < n; i++)
{
size_t len_i = com->tokens[i][1] - com->tokens[i][0] + 1;
argv[i] = argp;
memmove(argv[i], com->tokens[i][0], len_i);
argv[i][len_i] = '\0';
argp += len_i + 1;
}
assert(argp == args + req_size);
argv[i] = 0; // Null terminate list of pointers
print_argv(i, argv);
return 0;
}
输出:
fixed:
5: [command] [arg1] [arg2] [arg3] [arg4]
argv:
0: [command]
1: [arg1]
2: [arg2]
3: [arg3]
4: [arg4]
5: [<<NULL pointer>>]