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

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

How to convert variadic arguments to array in C

问题

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

  1. int run_command(char **output, int *retval, const char *command, const char* const args[])
  2. {
  3. ...
  4. pid_t pid = fork();
  5. if (pid == 0) {
  6. ...
  7. execvp(command, (char * const *)args);
  8. }
  9. ...
  10. }
  1. char *output;
  2. int retval;
  3. const char *command = "find";
  4. const char* const args[] = { command, "/tmp", "-type", "f", NULL };
  5. run_command(&output, &retval, command, args);
  1. int run_command2(char **output, int *retval, const char *command, ...)
  2. {
  3. va_list val;
  4. const char **args = NULL;
  5. int argc;
  6. int result;
  7. // Determine number of variadic arguments
  8. va_start(val, command);
  9. argc = 2; // leading command + trailing NULL
  10. while (va_arg(val, const char *) != NULL)
  11. argc++;
  12. va_end(val);
  13. // Allocate args, put references to command / variadic arguments + NULL in args
  14. args = (const char **) malloc(argc * sizeof(char*));
  15. args[0] = command;
  16. va_start(val, command);
  17. int i = 0;
  18. do {
  19. fprintf(stderr, "Argument %i: %s\n", i, args[i]);
  20. i++;
  21. args[i] = va_arg(val, const char *);
  22. } while (args[i] != NULL);
  23. va_end(val);
  24. // Run command, free args, return result
  25. result = run_command(output, retval, command, args);
  26. free(args);
  27. return result;
  28. }
  1. char *output;
  2. int retval;
  3. 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):

  1. int run_command(char **output, int *retval, const char *command, const char* const args[])
  2. {
  3. ...
  4. pid_t pid = fork();
  5. if (pid == 0) {
  6. ...
  7. execvp(command, (char * const *)args);
  8. }
  9. ...
  10. }

The function is called like this:

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

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

  1. int run_command2(char **output, int *retval, const char *command, ...)
  2. {
  3. va_list val;
  4. const char **args = NULL;
  5. int argc;
  6. int result;
  7. // Determine number of variadic arguments
  8. va_start(val, command);
  9. argc = 2; // leading command + trailing NULL
  10. while (va_arg(val, const char *) != NULL)
  11. argc++;
  12. va_end(val);
  13. // Allocate args, put references to command / variadic arguments + NULL in args
  14. args = (const char **) malloc(argc * sizeof(char*));
  15. args[0] = command;
  16. va_start(val, command);
  17. int i = 0;
  18. do {
  19. fprintf(stderr, "Argument %i: %s\n", i, args[i]);
  20. i++;
  21. args[i] = va_arg(val, const char *);
  22. } while (args[i] != NULL);
  23. va_end(val);
  24. // Run command, free args, return result
  25. result = run_command(output, retval, command, args);
  26. free(args);
  27. return result;
  28. }

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:

  1. char *output;
  2. int retval;
  3. 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:

确定