创建一个接受不同数据类型参数的C函数

时间:2013-07-16 02:48:35

标签: c function

我对C编程语言比较陌生,我正在试图弄清楚如何创建一个可以接受不同类型数据作为参数的函数。该函数应该计算并返回字符或整数数组中的元素数。我已经有两个单独的函数可以执行此操作,但我真的希望能够为这两个任务使用一个函数。有没有办法在C中做到这一点?

提前致谢!

6 个答案:

答案 0 :(得分:6)

C中没有标准函数重载(也没有模板),但你可以查看“类似printf”的函数(或variadic functions),也许他们可以做你需要的。如果他们允许灵活的参数列表。

这样一个函数的示例here采用可变大小的整数数组。

也许您可以通过以下方式使用void iterate(const char* format, ...);等函数签名:

iterate("char", some_char_array); // for char arrays/strings

或者

iterate("int", some_int_array); // for integer arrays

Aniket提出了一个很好的观点,你如何计算整数数组中的元素?如果你传递一个int数组作为参数,你也需要传递大小,这会破坏计算数组中元素的目的(正如你已经知道的那样,即大小)。

我假设你不知道大小,但你在数组中有一个终结符值(例如-1)。

在我考虑到上述假设的情况下,我已经快速攻击了你所需要的东西。

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

int iterate(const char* format, ...)
{
    va_list ap;
    va_start(ap, format);

    if (strcmp(format, "char") == 0)
    {
        char* array = va_arg(ap, char*);

        return strlen(array);
    }
    else if (strcmp(format, "int") == 0)
    {
        int j = -1;
        int* int_array = va_arg(ap, int*);
        while (int_array[++j] != -1)
                    ;     
        return j;
    }
    return 0;
}

int main()
{
    printf("%d\n", iterate("char", "abcdef"));
    int arr[] = {5, 4, 3, 2, 1, 0, -1};
    printf("%d\n", iterate("int", arr));

    return 0;
}

打印:

$ ./a.out 
6
6

答案 1 :(得分:3)

因此,我们假设您的两个函数名为sizeof_char_arraysizeof_int_array

在C11中,有一个名为“泛型选择”的新功能,可以让你用一个相对简单的宏做你想做的事情:

#define sizeof_array(X) \
    _Generic (*(X), \
              char: sizeof_char_array, \
              default: sizeof_int_array) (X)

(我甚至没有C11实现来测试这个,所以需要注意!)

在C11之前,有时使用常规命名函数的宏来完成。您可以根据宏参数提示定义一个将调用一个函数或另一个函数的宏:

#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x)

int a[] = { 1, 2, 3, 4, -1 };
char b[] = "abc";

sizeof_array(int, a);   /* macro expands to sizeof_int_array(a) */
sizeof_array(char, b);  /* macro expands to sizeof_char_array(b) */

如果输入参数确实是一个数组,则可以使用宏直接计算其大小:

#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0))

对于数组,以下表达式为真:

(void *)arr == &arr

因为数组的地址在内存中的位置与其第一个元素的地址相同。

因此,宏计算:sizeof(arr)/sizeof(arr[0])。由于sizeof运算符报告其参数的大小(以字节为单位),因此计算的表达式将导致数组中的元素数。但是,如果您使用标记来计算长度,ARRAY_SZ宏将导致大小至少比搜索到的标记遍历数组的长度大一个。

如果参数不是数组,则表达式导致除以0异常。

答案 2 :(得分:2)

在任何一种情况下,您都需要某种类型推理系统来告诉C编译器调用哪个函数。这意味着,您需要事先了解可能作为参数发送到您的“超级功能”的数组类型。

C中没有“自动类型推理”可以让您在运行时反映数据类型。更好的是,您可能必须编写自己的运行时环境才能实现此目的。

这是一种略微琐碎的hackish方式:

#include <stdio.h>

size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes)
{
   return sizeOfTheArrayInBytes/sizeOfOneElementInArray; 
}
int main(int argc, char *argv[])
{
   char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'};
   int iArr[5] = {10,20,30,40,50};
   printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)),
                                                               GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr)));
   return 0;
}

答案 3 :(得分:2)

答案很简单。您确实需要一个功能来执行此任务。试试这段代码

#define len(array) sizeof(array)/sizeof(array[0])

就是这样。

答案 4 :(得分:1)

您应该使您的函数参数采用void *类型。这样,您可以传入不同类型的数据,并将其类型转换为您想要的数据。但是,您需要注意,因为无法保证正确“猜测”void*指向的类型。

答案 5 :(得分:0)

这是不可能的,但是您可以使用并集(或结构)来模仿它。我只是使用doublechar数组,只是为了保持简单:

typedef union {
    double number;
    char * str;
} wild;

void foo_bar(wild w) {
    // ...do something with w.number or w.str...
}

要初始化wild,请执行以下操作:

wild w = {.str = "Hello world"};
//or 
wild w = {.number = 2.34};

唯一的问题是必须有一种知道它是数字还是字符串(字符数组)的方法。我找不到自动执行此操作的合理方法,因此,如果有人找到了,请告诉我。