如何在C语言中将数组作为参数列表传递给具有可变参数数量的函数?

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

How can I pass an array as a list of args to a function with varying number of parameters in C

问题

我想知道如何在C语言中将数组拆分为函数的多个参数。在看到Go语言中令人惊叹的语法糖后,我开始思考这个问题。

C代码如下:

#include <stdio.h>
#include <stdarg.h>

// 断言:所有参数都是有效的整数
void printEach(int len, ...) {
    // 不相关,这个函数打印它们的参数
    // 我知道如何使用va_start、va_arg...
}

void handleVet(int* v, int n) {
    // **这里是我的问题!!!**
    printEach(n, v[0]...[n]) // <----------- 非C代码。我需要它。
}

int main(void) {
    int v[] = {12,14,15,15};
    // 我之所以能这样做,是因为向量是静态的。我在编码时知道长度
    printEach(4, v[0],v[1],v[2],v[3]);
    // 但是如果我们想象一个任意的向量,就会有问题
    handleVet(v, 4);
    return 0;
}

以Go语言为例,代码如下:

package main

import "fmt"

func printEach(v ...int64) {
    // 不相关,这个函数打印它们的参数
}

func main() {
    arr := []int64{1,14,15}
    printEach(arr...)
}

我该如何在C语言中实现类似于"printEach(arr...)"的效果

英文:

I wonder how can I tease out an array in C to several arguments of a function.
After I saw the amazing syntatic sugar from Go (golang) I thinking about it.

The c code:

#include &lt;stdio.h&gt;
#include &lt;stdarg.h&gt;

// assert: all args are valid ints
void printEach(int len, ...) {
    	// Irrelevant, this function print their arguments
	    // And I know how to use va_start, va_arg...
}

void handleVet(int* v, int n) {
   // **HERE is my the question!!!**
   printEach(n, v[0]...[n]) // &lt;----------- NON-C code. I need it.
}

int main(void) {
	int v[] = {12,14,15,15};
	//I can do that only because the vector is static. I know the len when I&#39;m coding
		printEach(4, v[0],v[1],v[2],v[3]);
	// But if we imagine an arbitrary vector, we got a problem 
       handleVet(v, 4);
	return 0;
}

By Example, in go it would be:

package main

import &quot;fmt&quot;

func printEach (v ...int64) {
	// Irrelevant, this function print their arguments
}

func main() {
	var arr []int64 = []int64{1,14,15,}
	printEach(arr...)
}

How can I achieve the same effect of "printEach(arr...)" in C?

答案1

得分: 0

你需要指定数组的大小。以下是可能的代码示例:

void printEach(int* values, int size)
{
  if(size==0)
    return;
  printf("%d", values[0]);
  printEach(values+1, size-1);
}

这段代码的作用是递归地打印数组中的每个元素。函数接受一个指向整型数组的指针 values 和数组的大小 size。如果数组大小为0,则函数直接返回。否则,它会打印数组的第一个元素,然后递归调用自身,传入指向下一个元素的指针和数组大小减1的值。这样就能依次打印数组中的每个元素。

英文:

You will need to specify the size of the array. Here's what it might look like:

void printEach(int* values, int size)
{
  if(size==0)
    return;
  printf(&quot;%d&quot;, value[0]);
  printEach(values+1, size-1);
}

答案2

得分: 0

这是一个关于C语言中可变参数(vararg)如何工作的基本示例。
我无法参考你的Go示例,因为我不理解你的代码在做什么。希望这个最简示例足够清楚。如果你有任何问题,请问我,我会进行编辑。

void Foo(size_t sizeParamAmount, char *types, ...);
void Foo(size_t sizeParamAmount, char *types, ...)
{
    size_t i;
    float fTmp;
    int iTmp;    
    va_list vlArgList;

    va_start (vlArgList, sizeParamAmount);

    for (i = 0; i < sizeParamAmount; i++)
    {
        switch (types[i])
        {            
            case 'i':
                iTmp = va_arg (vlArgList, int);
                break;
            case 'f':
                fTmp = va_arg (vlArgList, float);
                break;
            default:
                return;//error
        }
    }
    va_end(vlArgList);
}

在阅读了你的编辑之后:

就像我在最简示例中所做的那样,你可以在可变参数之前传入一个指针,解释每个参数的类型。所以你可以这样调用Foo

Foo (3, "ifi", 3, 5.973, 92);

在阅读了你对另一个答案的评论之后,我明白了你的问题。

在这种情况下,你只需要传入一个指针(或者没有[]的数组,在这种情况下行为相同),它保存了一个结束内容标记。

无论如何,有一种方法,但你必须使用预处理标记进行操作。

对于你的需求来说,这种方法过于复杂了。不过,这个答案会给你所需的表示法。你需要通过sizeof(yourarray)来设置PRED的限制,并让OP获取单个元素。

https://stackoverflow.com/a/10542793/2003898

但是很遗憾,没有更简单的示例了。

英文:

This is a rudimentary example on how vararg is working in C.
I wasn't able to take refference to your go example as I don't udnerstand what your code does. I hope this minimal example is clear enough. If you have any questions ask me and I will edit it in.

void Foo(size_t sizeParamAmount, char *types, ...);
void Foo(size_t sizeParamAmount, char *types, ...)
{
    size_t i;
    float fTmp;
    int iTmp;    
	va_list vlArgList;

    va_start (vlArgList, sizeParamAmount);

	for (i= 0; i&lt; sizeParamAmount; i++)
	{
        switch (types[i])
		{			
			case &#39;i&#39;:
				iTmp = va_arg (vlArgList, int));
				break;
			case &#39;f&#39;:
				fTmp = va_arg (vlArgList, float));
				break;
            default:
                return;//error
        }
    }
    va_end(vlArgList);
}

After reading your edit:

As I already did in my minimal example, you can hand in a pointer before the var_arg's which is explaining which argument is of what type. so you could call Foo this way:

Foo (3, &quot;ifi&quot;, 3, 5.973, 92);

And after reading your comment to another answer I got what you are asking about.

In that case you really jsut should hand in a pointer (or array without [] behaves for this case the same) which holds an end content token.

Anyway there is a way. but you had to freak around with preprocessing tokens.

And would be totally over the top for your needs. This answer would anyway give you the requested notation. you had to set for PRED a limit by sizeof(yourarray) and the let OP take the single elements.

https://stackoverflow.com/a/10542793/2003898

But there is sadly not a more minimal example.

答案3

得分: 0

你正在寻找Variadic函数,你应该查看stdarg.h和varargs.h

英文:

You are looking for Variadic function, you should look at
stdarg.h and varargs.h

huangapple
  • 本文由 发表于 2014年12月18日 21:13:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/27547433.html
匿名

发表评论

匿名网友

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

确定