【C/C++】 变参函数

#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
 
#define MLA_ASSERT(expr)    (int)((!!(expr)) && (printf("assert fail: \"%s\" @ %s, %u", #expr, __FILE__, __LINE__), printf("\r\n"), Abort()))
 
int Abort(void)
{
    printf("reset reboot!\n");
    // 重启代码
}
 
/**
 * 按自定义格式符解析数据
 */
void process(const char *fmt, va_list args)
{
    CHECK(fmt != NULL);

    for (; *fmt; fmt++) {
        if (*fmt == '%') {
            switch (*++fmt) {
                case 'a':
                case 's': {
                    char *str = va_arg(args, char *);
                    printf("%s", str);
                    continue;
                }
                case 'b': {
                    float *num = va_arg(args, float *);
                    printf("%f", *num);
                    continue;
                }
                case 'f': {
                    float num = va_arg(args, double);  // 解析浮点数须用double,不能用float
                    printf("%f", num);
                    continue;
                }
                default:
                    printf("%c", *fmt);
                    continue;
            }
        } else {
            printf("%c", *fmt);
        }

    }
}
 
/**
 * 自定义可变参数函数
 * @param  hint: 传递给函数的额外参数
 * @param  fmt:  自定义格式符
 */
void VariadicFunction(char *hint, const char *fmt, ...)
{
    MLA_ASSERT(hint == NULL);
    MLA_ASSERT(fmt == NULL);
 
    // 定义一个参数列表
    va_list args;
    // 初始化列表参数args,第二个参数是可变参数前的第一个固定参数,即省略号前的第一个参数
    va_start(args, fmt);
    // 解析数据
    process(fmt, args);
    // 释放可变参数列表
    va_end(args);
    // 额外参数处理
    printf("%s, hint: %s\n",  __func__, hint);
}
 
/**
 * 带缺省参数可变参数函数
 * @param  hint: 传递给函数的额外参数
 * @param  isPrint:  带缺省属性的参数
 * @param  number:  带缺省属性的参数
 *
 * @note  带缺省属性的参数得从右边开始,函数声明时不能带缺省值
 */
void DefaultVariadicFunction(char *hint, bool isPrint = false, int number = 666)
{
    MLA_ASSERT(hint == NULL);

    printf("%s, hint: %s\n", __func__, hint);
    if (isPrint) {
        printf("%s, This is a function with default arguments: %d\n", __func__, number);
    }
}
 
void PackageFormattingData(char *hint, const char *fmt, ...)
{
    MLA_ASSERT(hint == NULL);
    MLA_ASSERT(fmt == NULL);

    char buf[256] = { 0 };
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    printf("%s, hint: %s\n",  __func__, hint);
    // file_write(buf);
    printf("%s, content: %s\n",  __func__, buf);
}

int main() 
{
    float f = 6.66;
    VariadicFunction("Here's a hint!", "%a%b%f%a", "string1", &f, 9.99, "STRING2");
    DefaultVariadicFunction("Here's a hint!");
    DefaultVariadicFunction("Here's a hint!", true);
    DefaultVariadicFunction("Here's a hint!", true, 999);
    PackageFormattingData("Can be used for writing files!", "%d, %f, %c, %s", 666, 88.88, 'C', __func__);
    PackageFormattingData("Can be used for writing files!", "%c, %s", 'F', "You can refer to the use of files as logs on the back end.");
    return 0;
}

 

自定义变参函数需要加入参数格式检查,以便在编译期就发现问题,避免运行时参数问题导致的异常

Function Attributes - Using the GNU Compiler Collection (GCC)

void __attribute__((format(printf,2,3))) VariadicFunction(char *hint, const char *fmt, ...)
{
    MLA_ASSERT(hint == NULL);
    MLA_ASSERT(fmt == NULL);
 
    // 定义有个参数列表
    va_list args;
    // 初始化列表参数args,第二个参数可变参数前的第一个固定参数,即略号前的第一个参数
    va_start(args, fmt);
    // 解析数据
    process(fmt, args);
    // 释放可变参数列表
    va_end(args);
    // 额外参数处理
    printf("%s, hint: %s\n",  __func__, hint);
}

VariadicFunction("Here's a hint!", "function name: %s");

加了参数格式化检查就会在编译时给出一个warning

 

 

posted @ 2023-04-24 16:23  壹点灵异  阅读(53)  评论(0编辑  收藏  举报