首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何在C函数中使用__VA_ARGS__而不是宏?

在C函数中使用VA_ARGS而不是宏的方法是通过宏定义来实现。VA_ARGS是C语言中的一个特殊宏,用于表示可变参数的占位符。下面是一个示例代码:

代码语言:c
复制
#include <stdio.h>
#include <stdarg.h>

void myFunction(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

#define myFunctionWithArgs(format, ...) myFunction(format, __VA_ARGS__)

int main()
{
    myFunctionWithArgs("Hello, %s!\n", "world");
    myFunctionWithArgs("The sum of %d and %d is %d.\n", 3, 4, 7);
    return 0;
}

在上面的示例中,我们定义了一个名为myFunction的函数,它接受一个格式字符串和可变参数。通过使用va_list、va_start、vprintf和va_end等宏,我们可以在函数内部处理可变参数。

为了更方便地使用可变参数,我们定义了一个名为myFunctionWithArgs的宏,它将格式字符串和可变参数传递给myFunction函数。这样,我们就可以像调用普通函数一样调用myFunctionWithArgs宏。

这种方法可以让我们在C函数中使用可变参数,而不需要直接使用VA_ARGS宏。这样做的好处是可以提高代码的可读性和可维护性。

腾讯云相关产品和产品介绍链接地址:

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

c语法】##__VA_ARGS__与__VA_ARGS__

引言 在调试过程,我们经常会自定义打印,比如日志信息的输出,这时就会用VA_ARGS,接下来详细讲解! VA_ARGS __VA_ARGS__C语言设定的一个预定义,用于处理可变参数的参数列表。...通常用在定义,以便可以接收不定数量的参数,并将他们作为整体处理。...通常的函数参数列表都是固定的,但也存在着不定参数数量的函数:printf ,为了定义可以处理不同参数个数的C99标准引入了 VA_ARGS,下列的代码均在C99及C99以上标准的环境下运行。...__VA_ARGS__表示所有在调用传递的额外参数。...##VA_ARGS 大家在了解__VA_ARGS__时,一定会看到有些地方在该定义前使用 ## 运算符来处理可变参数,: #define DEBUG_LOG(fmt, ...) \ printf

9410
  • 【为正名】99%人都不知道的##里用法

    这个系列将本着实用的原则介绍一些在模块封装“点石成金”的用法,让大家正确认识到真实的作用和使用规则——真真正正还“”一个公道。...(不是__name本身)粘连在一起,就需要“##”运算的帮助。...其实,可变参数列表最初诞生的原因之一是为了解决与C函数的可变参数(va_args)配合使用的问题,例如: #define log_info(__STRING, ...)...xxxx_init((NULL,##__VA_ARGS__)) 为消息处理提供默认的掩码配置 有些消息处理函数可以批量的处理某一类消息,具体选中了哪些消息类别,则通常由二进制掩码来表示,例如: typedef..., 0xFF00 ), ) 【结语】 ---- 不是阻碍代码开发和可读性的魔鬼,对自己不熟悉知识的傲慢才是。

    3.9K20

    提高代码逼格的利器:定义-从入门到放弃

    ,那么 __cplusplus 将不存在,其中的 extern "C" 将会被忽略; 如果使用 g++ 来编译,那么 __cplusplus 就存在,其中的 extern "C" 就发生作用,编译出来的函数名...在使用 MSVC 编译动态库时,需要在编译选项(Makefle 或者 CMakeLists.txt)定义 LIBA_API_EXPORTS,那么导出函数 hello 的最前面的 LIBA_API...此时,使用来实现的优势就体现出来了:因为没有类型的概念,调用者传入任何数据类型都可以,然后在后面的比较操作,大于或小于操作都是利用了 C 语言本身的语法来执行。...在 C++ ,这样的操作可以通过参数模板来实现,所谓的模板也是一种代码动态生成机制。当定义了一个函数模板后,根据调用者的实参,来动态产生多个函数。...printf(__VA_ARGS__) debug1("this is debug1: %d \n", 1); 如果在三个点(...)的前面加上了一个参数名,那么在使用时就一定要使用这个参数名,不能使用

    1.1K40

    变参函数和可变参数

    在 V4.0 版本,我们继续改进,使用 vprintf 函数实现我们的打印功能。vprintf 函数的声明在 stdio.h 头文件。...61.什么是可变参数 在上面的教程,我们学会了变参函数的定义和使用,基本套路就是使用 va_list 、 va_start 、 va_end 等,去解析那些可变参数列表我们找到这些参数的存储地址后...其实,C99 标准已经支持了这个特性,但是其它的编译器不太给力,对 C99 标准的支持 不是很好,只有 GNU C 支持这个功能,所以有时候我们也把这个可变参数看作是 GNU C 的一个语法扩展。...可变参数使用 C99 标准新增加的一个 VA_ARGS 预定义标识符来表示前面的变参列表,不是像变参函数一样,使用 va_list 、va_start 、 va_end 这些去解析变参列表。...上面这种格式是 GNU C 扩展的一个新写法。我们不再使用 VA_ARGS ,而是直接使用 args... 来表示一个变参列表,然后在后面的定义,直接使用 args 代表变参列表就可以了。

    1.8K20

    STM32单片机极简方法 使用定义 代替复杂的重定向printf()函数,实现串口打印。(HAL库例程)

    对于 printf() 函数我们并不陌生,初学C语言使用的第一个函数,其作用是在终端打印显示格式化字符串。...但是如果我们使用的是单片机运行C语言代码,如果不经任何修改直接使用 printf() 函数,结果是什么现象都没有。...#endif 以上代码表示用 ps() 这个函数代替HAL库的串口发送函数,并且可以使用格式控制符%c,%d,%f,\r,\n等可变参数控制符。...ps()函数使用方法如下: while (1) { num++; ps("串口打印函数 \r\n");//无参数打印,\r\n表示换行 ps("num = %d \r\n",num);...的定义形式。也就是说定义的__VA_ARGS__会被替换成"..." #define ps(format,...)

    2.1K20

    Google Mock(Gmock)简单使用和源码分析——源码分析

    上述代码第17行定义了一个具有mutable属性的变量,之所以使用mutable是因为它可能会被使用在const类型的函数,然而该对象的方法并不一定是const的。...比如例子Online方法,它被mock之后,传导到该类的R就是bool。上面代码05行使用返回类型重新定义了函数类型为F()。06行别名了用于保存函数参数的元组类型为ArgumentTuple。...我们先看和mock函数同名的函数的参数定义,它使用了GMOCK_ARG_指定参数类型 #define GMOCK_ARG_(tn, N, ...) \ tn ::testing::internal...2函数使用gmock和函数名联合组装成的新函数名,它返回了一个被参数筛选的函数对象。EXPECT_CALL和ON_CALL中就是调用了它。...执行         当我们调用mock的类的mock的函数时,将会调用到MOCK_METHOD系列定义的函数

    4.3K20

    【为正名】什么?我忘了去上“数学必修课”!

    在前面的文章《【为正名】本应写入教科书的“世界设定”》我们了解到:会在预编译阶段被“处理掉”——会被逐级展开、其最终代表的字符串会被替换到对应的文本文件(只不过通常这个文本文件就是".c"文件...举个例子: 定义三个独立的,分别代表三个独立的“数字”: #define NUM_A 2 #define NUM_B 5 #define NUM_C 5 借助上一篇文章引入的胶水...的元素一个一个手工加入到链表(添加到 s_ptListRoot 指向的链表)——这里的代价是双份的: 初始化函数所占用的代码空间 和 添加节点的运行时间。...所谓的重载是说:我们不必亲自去数要粘贴的字符串的数量“手工选取正确的版本”,直接让编译器自己替我们挑选。...;"part1" CONNECT2() 的作用就是将 字符串“CONNCET”与这个数组组合起来变成一个新的“参数的名字”; "part2" 的作用则是给这个组装出来的参数传递参数。

    67720

    Linux kernel中常见的整理

    的一些奇技淫巧:https://gaomf.cn/2017/10/06/C_Macro/ 以下是整理的一些linux kernel的常见,由于不同体系架构,或者不同模块的定义不同,只挑选了其中容易看懂的作为记录...避免使用goto,对程序流进行统一的控制,使用break跳出 避免空引起的warning 定义一个单独的函数块来实现复杂的操作 0x01 常见整理 __CONCAT "##"用于粘贴两个参数,"#...如果不是常量表达式,则会使用第二个操作数void类型。...这就阻止了cpu将寄存器和cache的数据用于去优化指令,避免去访问内存。...通常X86 CPU更新内存都使用Write-Back策略。 #ifdef ASSEMBLY 一些常量同时在汇编和C使用,然而,我们不能像注释C的常量那样加一个“UL”或其他后缀。

    2K50

    Linux kernel中常见的整理

    的一些奇技淫巧: https://gaomf.cn/2017/10/06/C_Macro/ 以下是整理的一些linux kernel的常见,由于不同体系架构,或者不同模块的定义不同,只挑选了其中容易看懂的作为记录...避免使用goto,对程序流进行统一的控制,使用break跳出 避免空引起的warning 定义一个单独的函数块来实现复杂的操作 0x01 常见整理 __CONCAT "##"用于粘贴两个参数,"#...如果不是常量表达式,则会使用第二个操作数void类型。...这就阻止了cpu将寄存器和cache的数据用于去优化指令,避免去访问内存。...通常X86 CPU更新内存都使用Write-Back策略。 ifdef ASSEMBLY 一些常量同时在汇编和C使用,然而,我们不能像注释C的常量那样加一个“UL”或其他后缀。

    1.7K20

    一文读懂Define的所有用法

    ) x##n //标识把两个语言符号连在一起 形成新的 xn int XNAME(1) = 10; //int x1=10;#define DoSum(a,b,c) do \ {\ c = a...define" <<endl; #endif //编译时,可以在makefile添加定义选项进行传递 ,使用 -D参数 -DDEBUG 比如: gcc -DDUBG//可以直接在代码中使用。...__FILE__ //在预编译时会替换成当前的源文件名 __LINE__ //在预编译时会替换成当前的行号 __FUNCTION //__在预编译时会替换成当前的函数名称 2.阅读方便undefined...有时候定义只是为了阅读方便起到注释作用,并没有实际含义,: 3.字符串指示与连接 4.多行预定义undefined一般用来预定一个类函数的语句块。...主要是为了使用方便。 5.可变变量 6.条件定义 7.其他系统定义

    1.5K20

    iOS的预编译指令的初步探究

    C分为两类,对象(object-like macro)和函数(function-like macro)。对于对象来说确实相对简单,但却也不是那么简单的查找替换。...注意函数必须是有意义的运算,因此你不能直接写AB来连接两个参数,需要写成例子的A##B。还有一切其他的自成一脉的运算符号,我们稍后还会介绍几个。...如果我们在申明这个的时候没有指定format参数,直接使用参数列表,那么在使用不写参数的NSLog()也将被匹配到这个,导致编译无法通过。...使用-W...的形式,不是在UI上勾选的一大好处是,在编译器版本更新时,新加入的警告如果包含在-Wall的话,不需要对工程做任何修改,新的警告即可以生效。...在方法导航哪里就会出现你的mark了 是不是很方便呀 如果使用了 "#pragma mark -" 这样: #pragma mark - #pragma mark 这里是applicationWillTerminate

    2.3K80

    从零开始学C++之从CC++(一):const与#define、结构体对齐、函数重载name mangling、newdelete 等

    : 常变量在定义时必须初始化; 常变量初始化之后,不允许再被赋值; 正如我在这里所说,其实加了关键字const只是提示编译器这个变量是常量,如果我们在接下来的操作中试图更改它,编译器会报错,不是真正的常量...+ 尽量用const、enum替换#define定义常量,用inline 替换带参数的定义;但 #define 在底层编程是必不可少的,下面举个例子: #include using...参数定义的意义就很清楚了,查看下输出即可。 我们知道printf函数带有可变参数,函数定义也可以带可变参数,同样是在参数列表中用...表示可变参数。...printf("x>y") : printf("x is %d but y is %d", x, y)); 在定义,可变参数的部分用__VA_ARGS__表示,实参对应...的几个参数可以看成一个参数替换到定义...extern “C” 可以实现CC++混合编程,被extern "C" 修饰的变量和函数是按照C语言方式进行编译和链接的,即对C语言写的函数不进行改名,一般在 C的头文件中使用,如果头文件被C代码包含并用

    1.2K00

    ReactiveCocoa 奇妙无比的 “” 魔法

    计算机语言C语言或汇编语言有简单的系统,由编译器或汇编器的预处理器实现。C语言的预处理器的工作只是简单的文本搜索和替换,使用附加的文本处理语言M4,C程序员可以获得更精巧的。...Lisp类语言Common Lisp和Scheme有更精巧的系统:的行为如同是函数对自身程序文本的变形,并且可以应用全部语言来表达这种变形。...: RACTupleNil.tupleNil,复制代码 注意这里结尾是“,”逗号,不是“;”分号,原因是因为tupleWithObjectsFromArray:方法里面是各个元素,所以这里用“;”分号就会出错...3.strchr函数原型如下: extern char *strchr(const char *s,char c);复制代码 查找字符串s首次出现字符c的位置。...在实际使用过程,这不是一个问题,因为@onExit后面如果没有大括号,那么它是一个无用的结构,不会有任何事情发生。 最后 关于ReactiveCocoa里面所有的实现分析都已经分析完成。

    2.8K30

    C语言边角料-01

    1999 年,C语言的标准化委员会发布了 C99 标准,引入了许多特性,包括可变长度的数组、灵活的数组成员(用在结构体)、对IEEE754浮点数的改进、指定成员的初始化器、内联函数、支持不定参数个数的定义...于是最近找了一本比较新的 C 语言书籍翻了一下,发现很多比较偏僻的语法,很少被使用到,包括 C99 标准的一些内容,所以我想把这部分内容整理一下,也是让自己对这一门古老的语言重新梳理一下。...结构体的 data 成员是一个指针变量,需要单独为它申请一块空间才可以使用。而且在结构体使用之后,需要先释放 data,然后释放结构体指针 ams,顺序不能错。这样使用起来,是不是有点麻烦?...不定参数的定义 定义的参数个数可以是不确定的,就像调用 printf 打印函数一样,在定义的时候,可以使用三个点(...)来表示可变参数,也可以在三个点的前面加上可变参数的名称。...printf(__VA_ARGS__) debug1("this is debug1: %d \n", 1); 如果在三个点(...)的前面加上了一个参数名,那么在使用时就一定要使用这个参数名,不能使用

    48520

    玩转iOS“定义”

    玩转iOS“定义”        定义在C类语言中非常重要,因为是一种预编译时的功能,因此其可以比运行时更高层面的对程序流程进行控制。...二、关于“定义”       使用#define来进行定义,定义分为两种,一种是对象式,一种是函数。...,看上去很完美,后面我们就使用这个函数为例,来深入理解的原理。...三、从一个简单的函数说起      再来看下上面我们编写的计算面积的,正常情况下好像没什么问题,但是需要注意,归根结底不是函数,如果完全把其作为函数使用,我们就可能会陷入一系列的陷阱,比如这样使用...对于不定参数的,借助##符号来拼接参数       在定义函数时,我们可以定义函数的参数为不定个数参数,定义函数时也类似,使用符号"..."

    3.4K11
    领券