变量参数在C中

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

Variable arguments in C

问题

有没有一种方法可以像读取argv[]中的命令行参数一样读取/访问变量参数?

我知道有一种使用va_arg的方法来做这件事,但只是想知道是否存在类似于"argv"的东西?

英文:

Is there a way to read/access variable arguments like we read command line arguments from argv[]?

I'm aware of the va_arg way of doing it but just wondering if something like "argv" exists for this?

答案1

得分: 2

C标准提供用于访问可变参数的唯一方法是va_arg方法。

一般情况下,除非对语言进行了某种严重的扩展,否则不可能存在任何形式的va_arg[i]方法来访问可变参数,因为va_arg[i]必须具有一个固定的类型,而可变参数可以具有任何完整的对象类型。

C实现可以通过将参数连续地组织到内存中来实现<stdarg.h>的特性,然后您可以访问该内存,包括将其视为具有相同类型的所有可变参数的数组。然而,这样做的方式不仅不具备对其他C实现的可移植性,而且通常不会得到特定C实现的支持。

英文:

The only facility the C standard provides for accessing variable arguments is the va_arg method.

In general, it would be impossible (barring some gross extension to the language) for there to be any sort of va_arg[i] method of accessing variable arguments since va_arg[i] must have one fixed type but variable arguments can have any complete object type.

A C implementation might implement the &lt;stdarg.h&gt; features by organizing arguments into memory serially, and then it could be possible to access that memory yourself, including accessing it as an array of all the variable arguments have the same type. However, the means for doing so would not only not be portable to other C implementations but generally would not be supported by the specific C implementation.

答案2

得分: 1

实际上,是的有一种方法

...通过宏技巧。
#include &lt;stdio.h&gt;

// foo是一个宏,它将接受多个字符串并将它们传递给_foo
#define foo(...) _foo( sizeof((char *[]){__VA_ARGS__}) / sizeof(char *), (char *[]){__VA_ARGS__})

void _foo(int argc, char *argv[])
{
	printf("argc: %d\n", argc);
	for (int i = 0; i < argc; i++)
	{
		printf("argv[%d]: %s\n", i, argv[i]);
	}
}

int main(void)
{
	foo("Hello", "World");
}

工作原理

它使用:

  • ...__VA_ARGS__:宏中可变参数的语法
  • (char *[]){/*...*/}:创建字符串数组的复合字面量
  • sizeof(array) / sizeof(elem):获取数组中元素的数量的技巧

foo从可变参数中创建了两个数组。第一个数组用于大小技巧,并传递给argc。第二个直接传递给argv

上面提到的两点已经在评论中由@Brian61354270和@Cubic指出,只是将整个过程放在一起。特别是@Cubic,他展示了相同的方法,但没有使用宏。

几个注意事项

  • va_arg不同,这个技巧只能在具有相同类型的参数时使用。
  • 这使用了一个宏。通常,这意味着宏参数可能会被多次评估。在这里,参数看起来像被评估两次,但sizeof不会评估。因此,调用foo(bar())将只调用一次bar。(这很好,这就是我们想要的)
  • 它的行为与mainargc/argv不完全相同。首先,我没有在argv的末尾放置NULL。不过,这很容易添加。
英文:

Actually, yes there's a way

...with macro tricks.
#include &lt;stdio.h&gt;

// foo is a macro that&#39;ll take multiple strings and pass them to _foo
#define foo(...) _foo( sizeof((char *[]){__VA_ARGS__}) / sizeof(char *), (char *[]){__VA_ARGS__})

void _foo(int argc, char *argv[])
{
	printf(&quot;argc: %d\n&quot;, argc);
	for (int i = 0; i &lt; argc; i++)
	{
		printf(&quot;argv[%d]: %s\n&quot;, i, argv[i]);
	}
}

int main(void)
{
	foo(&quot;Hello&quot;, &quot;World&quot;);
}

How it works

It uses:

  • ... and __VA_ARGS__: the syntax for variadic arguments in macros
  • (char *[]){/*...*/}: a compound literal to create a array of strings
  • sizeof(array) / sizeof(elem): a trick to get the number of elements in an array

The macro foo creates two arrays from the variadic parameters. The first array is used in the size trick, and passed to argc. The second is directly passed to argv.

Two of the above points have already been pointed out in the comments by @Brian61354270 and @Cubic, it was just a matter of putting the whole thing together. Especially @Cubic, who showed the same way but without a macro.

A few notes

  • Unlike with va_arg, this technique can only be used when you have arguments of the same type.
  • This uses a macro. Often, it implies that the macro arguments might be evaluated multiple times. Here it looks like the arguments are evaluated twice, but sizeof doesn't evaluate. So calling foo(bar()) will only call bar once. (Which is pretty good, that's what we want)
  • It doesn't behave exactly like the main's argc/argv. For starters, I didn't put NULL at the end of argv. That's trivial to add though.

答案3

得分: 0

你可能在提到像printf这样的函数,它可以在不同的时间接受不同类型的参数吗?

printf是一个可变参数函数的示例,声明如下:

printf(char* format, ...);

这里的...表示后续的参数可以是任何类型,且数量可以任意。

调用者使用类型va_list以及在头文件<stdarg.h>中定义的宏va_startva_argva_end来处理这些参数。

有很多在线示例可以解释如何使用它。

英文:

Are you perhaps referring to the way that functions like printf can take different arguments at different times?

printf is an example of a variadic function, and is declared as:

printf(char* format, ...); 

Where the ... means the following arguments can be of any type, and there can be any number of them.

These are processed by the caller using type va_list and macros va_start, va_arg and va_end, all defined in header file &lt;stdarg.h&gt;.

There are plenty of examples online that explain how this is used.

huangapple
  • 本文由 发表于 2023年7月27日 20:49:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76779904.html
匿名

发表评论

匿名网友

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

确定