C——特殊的函数处理

1.泛型函数

C11新增了关键字 _Generic,可用于处理泛型函数

用法

_Generic(x, int: "int", double: "double", default: "other");

编译器会根据传入的x来推断类型,然后与后面的标签匹配。

可结合宏定义来达到一定的泛型的目的

演示

#define get_type(x) _Generic(x, int: "int", double: "double", char: "char", default: "other")

假设有一个交换函数,我们可以在一个头文件中声明其不同的版本,然后再宏定义一个swap函数,标签对应的是函数指针。在其他文件中调用交换函数只需要调用宏定义版本的函数即可。

2.内联函数

宏函数有些像内联函数,抛开宏函数的特性,实际上二者也没有多少差别,定义方法和C++一样,声明,然后inline修饰定义函数,如果想让其具有内部链接性可用static修饰。

如果用static修饰函数,可以不用声明函数

演示

inline static void swap(int * a, int * b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

由于static的修饰,使得内联函数具有内部链接性,可考虑把内联函数封装在一个有文件中。

与C++不同的是,C允许内联函数和外部链接的函数混合使用。但是会优先调用用stati修饰的内部连接性的内联函数。只有inline修饰的函数则表明可被替换为外部定义的函数,但是能声明,否则会发生函数重复定义。

func.c

#include <stdio.h>
void func()
{
    printf("外部链接函数调用\n");
}

main.c

#include <stdio.h>

inline void func()
{
    printf("use func function\n");
}
int main()
{
    func();
    return 0;
}

 运行结果

3.不返回主函数的函数

C11新增的函数说明符 _Noreturn 

用法

_Noreturn void swap(int * a, int * b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main()
{
    int x,y;
    x = 10;
    y = 20;
    swap(&x, &y);
    printf("x is %d\ny is %d\n",x,y);
    return 0;
}

printf函数并不会被执行,而是直接退出程序。

exit函数就是这个函数的一个示例。

值得一提的是,虽然用_Noreturn修饰的函数不会返回主函数,但是其也有返回值声明,和普通函数一样,在默认的情况下是int,但是对于_Noreturn函数而言,编写程序的人有责任应该指定的声明其函数返回值为void,以免造成误解。

4.可变参数函数

要使用可变参数函数这一技术,要包含头文件stdargs.h

下面是一个方便说明的例子

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

inline static double sum(int args, ...)
{
    double ans = 0;
    va_list ap;
    va_list ap_copy;
    va_copy(ap_copy, ap);
    va_start(ap, args); //initialized ap to argument list
    //访问列表中的内容
    ans += va_arg(ap,int);
    ans += va_arg(ap,double);
    va_end(ap);
    return ans;
}
int main()
{
    double ans = sum(2,3,3.14);
    printf("%.2lf", ans);
    return 0;
}

1.首先,提供一个这样的函数原型

返回值类型 函数名(参数个数, ...)

...代表的是参数列表,也就是具体的参数

2.然后需要一个专门储存参数列表的类型,即va_list.

3.对其进行初始化使,即va_start函数,接受一个va_list变量和一个整形变量。作用是将va_list变量初始化为参数列表中的内容,即...中的内容

可以使用va_copy对va_list变量进行复制

4.使用va_arg宏函数具体的使用参数

第n次调用va_args会返回参数列表中的第n项。并且,这种操作是不可回溯的,所以,有时候可能用va_copy来进行va_list的对象拷贝。

5.进行清理操作

由于va_list内部存储是由malloc开辟的堆区空间,所以要进行内存的清理工作。

va_end对va_list变量进行内存的free操作,释放其所占的内存。

简单的demo

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

double sum(int, ...);

int main()
{
    double s, t;
    s = sum(3, 1.1, 2.5, 13.3);
    t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
    printf("s is %.2lf\nt is %.2lf\n",s,t);

    return 0;
}

double sum(int args, ...)
{
    va_list ap;
    double tot = 0;
    va_start(ap,args);
    for(int i=0;i<args;++i)
    {
        tot += va_arg(ap,double);
    }
    va_end(ap);
    return tot;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值