如何在C中将可变参数转换为数组

huangapple go评论75阅读模式
英文:

How to convert variadic arguments to array in C

问题

以下是您要翻译的代码部分:

int run_command(char **output, int *retval, const char *command, const char* const args[])
{
    ...
    pid_t pid = fork();
    if (pid == 0) {
        ...
        execvp(command, (char * const *)args);
    }
    ...
}
char *output;
int retval;
const char *command = "find";
const char* const args[] = { command, "/tmp", "-type", "f", NULL };
run_command(&output, &retval, command, args);
int run_command2(char **output, int *retval, const char *command, ...)
{
	va_list val;
	const char **args = NULL;
	int argc;
	int result;

	// Determine number of variadic arguments
	va_start(val, command);
	argc = 2; // leading command + trailing NULL
	while (va_arg(val, const char *) != NULL)
		argc++;
	va_end(val);

	// Allocate args, put references to command / variadic arguments + NULL in args
	args = (const char **) malloc(argc * sizeof(char*));
	args[0] = command;
	va_start(val, command);
	int i = 0;
	do {
		fprintf(stderr, "Argument %i: %s\n", i, args[i]);
		i++;
		args[i] = va_arg(val, const char *);
	} while (args[i] != NULL);
	va_end(val);

	// Run command, free args, return result
	result = run_command(output, retval, command, args);
	free(args);
	return result;
}
char *output;
int retval;
run_command2(&output, &retval, "find", "/tmp", "-type", "f", NULL);

请注意,这些是您提供的代码片段的翻译。

英文:

For a project of mine, I created a function to run external commands (reduced to what's important for my question):

int run_command(char **output, int *retval, const char *command, const char* const args[])
{
    ...
    pid_t pid = fork();
    if (pid == 0) {
        ...
        execvp(command, (char * const *)args);
    }
    ...
}

The function is called like this:

char *output;
int retval;
const char *command = "find";
const char* const args[] = { command, "/tmp", "-type", "f", NULL };
run_command(&output, &retval, command, args);

Now, I created a wrapper that uses variadic arguments instead of an array of arguments:

int run_command2(char **output, int *retval, const char *command, ...)
{
	va_list val;
	const char **args = NULL;
	int argc;
	int result;

	// Determine number of variadic arguments
	va_start(val, command);
	argc = 2; // leading command + trailing NULL
	while (va_arg(val, const char *) != NULL)
		argc++;
	va_end(val);

	// Allocate args, put references to command / variadic arguments + NULL in args
	args = (const char **) malloc(argc * sizeof(char*));
	args[0] = command;
	va_start(val, command);
	int i = 0;
	do {
		fprintf(stderr, "Argument %i: %s\n", i, args[i]);
		i++;
		args[i] = va_arg(val, const char *);
	} while (args[i] != NULL);
	va_end(val);

	// Run command, free args, return result
	result = run_command(output, retval, command, args);
	free(args);
	return result;
}

EDIT: note on do-while loop:<br/>
For the last element, this will result in fprintf(stderr, &quot;Argument %i: %s\n&quot;, i, NULL), which is valid on GCC and will print '(null)', but might be undefined on other compilers. Thanks to @GiovanniCerretani for pointing this out.

Which is called like this:

char *output;
int retval;
run_command2(&amp;output, &amp;retval, &quot;find&quot;, &quot;/tmp&quot;, &quot;-type&quot;, &quot;f&quot;, NULL);

The wrapper works fine (Linux/x64/GCC 9.2.0), but is this actually a valid way to convert variadic arguments to array? Or does this just work by accident?

The documentation on va_* is thin, e.g. there's no hint if a string retrieved using va_arg() remains valid when va_arg() is called again or when calling va_end().

答案1

得分: 3

你正在做的将按预期工作。

va_arg的调用使您能够访问传递给函数的char *参数。这些指针的值是传递给run_command2的,这意味着它们的范围至少在调用函数中是有效的。

因此,即使在调用va_end之后它们仍然有效。

英文:

What you are doing will work as expected.

The calls to va_arg get you access to the char * arguments that were passed to the function. The values of these pointers is what was passed to run_command2 meaning their scope is valid at least in the calling function.

So they are valid even after calling va_end.

答案2

得分: 0

以下是要翻译的内容:

由于这个主题上没有太多可用的信息,我决定实现我能想到的所有可能的包装器变体,并将它们放在一个 Gist 中:链接

希望这对其他面临相同任务的人有所帮助。

英文:

As there's not much available on this topic, I decided to implement all possible wrapper variants I could think of and put them in a Gist: Link

Hopefully this helps others facing the same task.

答案3

得分: -2

这个args = (const char **) malloc(argc * sizeof(char*));看起来很奇怪。我宁愿先分配char **args = malloc(sizeof(char*) * (argc));,然后再分配args[i] = malloc(sizeof(char) * (strlen(val) + 1));

你需要分配char **,然后为该数组中的每个字符串分配内存。

英文:

This args = (const char **) malloc(argc * sizeof(char*)); is quite strange. I would rather first allocate char **args = malloc(sizeof(char*) * (argc)); and then args[i] = malloc(sizeof(char) * (strlen(val) + 1));

You need to allocate the char ** and then allocate each string in this array.

huangapple
  • 本文由 发表于 2020年1月3日 17:39:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/59576159.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定