我对 C 编程语言比较陌生,我试图弄清楚如何创建一个可以接受不同类型数据作为参数的函数。该函数应该计算并返回字符或整数数组中的元素数。我已经有两个单独的函数可以做到这一点,但我真的希望能够为这两个任务使用一个函数。有没有办法在C中做到这一点?
提前致谢!
C 中没有标准的函数重载(也没有模板),但您可能可以查看“类似 printf”的函数(或可变参数函数),也许它们可以满足您的需求。如果有的话,它们允许灵活的参数列表。
这里有一个这样的函数示例,它采用可变大小的整数数组。
也许您可以有一个函数签名,例如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*);
va_end(ap);
return strlen(array);
}
else if (strcmp(format, "int") == 0)
{
int j = -1;
int* int_array = va_arg(ap, int*);
while (int_array[++j] != -1)
;
va_end(ap);
return j;
}
va_end(ap);
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
所以,让我们假设你的两个函数被调用sizeof_char_array
和sizeof_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 异常。
答案很简单。你确实需要一个函数来完成这个任务。试试这段代码
#define len(array) sizeof(array)/sizeof(*array)
就是这样。
重要说明:正如评论中所指出的,这不适用于动态分配的数组。
你应该让你的函数参数接受一个void *
类型。这样,您可以传入不同类型的数据,并将其类型转换为您想要的数据。但是,您确实需要注意,因为无法保证正确“猜测” avoid*
指向的类型。
无论哪种情况,您都需要某种类型推断系统来告诉 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;
}
这不太可能,但你可以建立一个标记工会
typedef struct {
union {
ssize_t i;
double d;
char *s;
} unknown;
char identity;
} Dynamic;
或者您可以使用 void 指针:
typedef struct {
void *unknown;
char identity;
} Dynamic;