Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C99】#,##,#__VA_ARGS__,##__VA_ARGS__

【C99】#,##,#__VA_ARGS__,##__VA_ARGS__

作者头像
用户11396661
发布于 2025-03-30 12:16:50
发布于 2025-03-30 12:16:50
7700
代码可运行
举报
文章被收录于专栏:C++开发C++开发
运行总次数:0
代码可运行

1.#运算符

#运算符用于将宏参数转换为字符串字面量。这通常用于调试或日志记录,将参数的值以字符串形式输出。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

#define LOG(para) printf("%d,%s\n",para,#para)

int main() {
    LOG(10);                
    return 0;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

// #define LOG(para) printf("%d,%s\n",para,#para)
#define str(x) #x

int main() {
    char* s=str(10);
    std::cout<<s;         
    return 0;
}

2.##运算符

## 运算符用于将两个标记(tokens)拼接成一个单独的标记。这在需要动态生成标识符时非常有用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define MAKE_ID(a, b) a##b

int main() {
    int value123 = 42;
    int id = MAKE_ID(value, 123);
    return 0;
}

3.#__VA_ARGS__

#__VA_ARGS__#__VA_ARGS__ 的组合,用于将可变参数列表转换为字符串。这在定义可变参数宏时非常有用,特别是在需要将参数列表作为字符串输出时。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define LOG(...) printf("Message: " #__VA_ARGS__)

int main() {
    LOG(Hello, world!);
    return 0;
}

4. ##__VA_ARGS__

##__VA_ARGS__##__VA_ARGS__ 的组合,用于处理可变参数为空的情况。当没有参数传递给宏时,## 会移除多余的逗号,避免语法错误。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

#define LOG(level, ...) printf(level, ##__VA_ARGS__)

int main() {
    LOG("Hello, world!","aaa");
    LOG("a");           
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【c语法】##__VA_ARGS__与__VA_ARGS__
在调试过程中,我们经常会自定义打印,比如日志信息的输出,这时就会用VA_ARGS,接下来详细讲解!
破晓的历程
2024/08/29
1.1K0
[C语言] #、##、__VA_ARGS__的使用
从网上借鉴了一些内容,然后整理了一下三者的区别,记录一下。 #include <iostream> // #: 用来把参数转换成字符串 #define LOG1(x) do { printf("%s=%d\n",#x,x); }while(0) // ##:用于将带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串;但它不可以是第一个或者最后一个子串。所谓的子串(token)就是指编译器能够识别的最小语法单元; #define LOG2(x) log##x() // __VA_ARGS_
轻舞飞扬SR
2021/03/15
1.1K0
《不定参数与不定宏参数:C++程序员必须掌握的灵活编程技巧》
在 C++ 中,不定参数函数(Variadic Functions) 是一种可以接受数量不确定的参数的函数。这种机制常用于像 printf 这样的标准库函数,也广泛应用于日志系统、格式化输出、通用容器构造等场景
IsLand1314
2025/05/01
730
C/C++开发基础——可变参数与可变参数模板
1.如果可变参数的参数类型相同,可以使用标准库中的initializer_list。
Coder-ZZ
2023/09/04
8790
C/C++开发基础——可变参数与可变参数模板
【Linux】日志函数
日志在程序设计中扮演着至关重要的角色,它不仅是程序运行情况的记录者,还是问题诊断、性能优化、安全审计以及用户行为分析的重要工具。本篇博客我们就设计一个日志函数,并在过程中学习一些知识。
破晓的历程
2024/08/29
2030
整理C/C++的可变参数
c语言中使用可变参数最熟悉应该就是printf, 其是通过...来从代码语句中表示可变化的参数表。
Rock_Lee
2020/09/21
5.7K0
日志代码编写
  日志是程序周期性运转或者特定时刻等一些常规或者特殊消息以特殊的形式打印出来,我们称为日志,关于日志,AI是这样回答的:
用户11029129
2024/11/02
1550
日志代码编写
可变参数(c/c++)
有时候我们在编写函数时,可能不知道要传入的参数个数,类型 。比如我们要实现一个叠加函数,再比如c语言中的printf,c++中的emplace_last()。
薄荷冰
2024/02/17
1.1K0
可变参数(c/c++)
C中的预编译宏定义
文章来自 http://www.uml.org.cn/c++/200902104.asp 在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译器处理之前, 预处理器首先对源程序中的"宏(macro)"进行处理. C初学者可能对预处理器没什么概念, 这是情有可原的: 一般的C编译器都将预处理, 汇编, 编译, 连接过程集成到一起了. 编译预处理往往在后台运行. 在
杨奉武
2018/04/18
3.1K0
【为宏正名】99%人都不知道的"##"里用法
有人说C语言中最臭名昭著的两兄弟就是指针和宏了。对于前者,很多有经验的老鸟会告诉你:用好了指针你就掌握了C语言的内功心法——如同原力一样,无论是追随光明还是堕入黑暗都离不开它。宏就没这么幸运了,不光年年受到邪恶的混乱C语言大赛的肆意霸凌(https://www.ioccc.org/),更是让“让代码爹妈都不认识”的身份标签贴到了骨头上——怎一个惨字了得。
GorgonMeducer 傻孩子
2020/07/28
4.1K0
【为宏正名】99%人都不知道的"##"里用法
va_start va_arg va_end 的原理与实例
func( Type para1, Type para2, Type para3, ... ) {       /****** Step 1 ******/       va_list ap;       va_start( ap, para3 ); //一定要“...”之前的那个参数**ap指向para后的第一个可变参数。       /****** Step 2 ******/       //此时ap指向第一个可变参数       //调用va_arg取得里面的值       Type xx = va_arg( ap, Type );        //Type一定要相同,如:       //char *p = va_arg( ap, char *);       //int i = va_arg( ap, int );       //如果有多个参数继续调用va_arg       /****** Step 3 ******/       va_end(ap); //For robust! } ◎研究: typedef char *    va_list;//va_list 等价于char*即字符指针。 #define va_start _crt_va_start//注意下面的替代。 #define va_arg _crt_va_arg #define va_end _crt_va_end #define  _crt_va_start(ap,v)    ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t)      ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap)        ( ap = (va_list)0 )  va_list argptr; C语言的函数是从右向左压入堆栈的,调用va_start后, 按定义的宏运算,_ADDRESSOF得到v所在的地址,然后这个 地址加上v的大小,则使ap指向第一个可变参数如图:          栈底 高地址     | .......          | 函数返回地址     | .......           | 函数最后一个参数     | ....                            | 函数第一个可变参数       <--va_start后ap指向      | 函数最后一个固定参数     | 函数第一个固定参数      栈顶 低地址 然后,用va_arg()取得类型t的可变参数值, 先是让ap指向下一个参数: ap += _INTSIZEOF(t),然后在减去_INTSIZEOF(t),使得表达式结果为 ap之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的 类型的指针,然后用*取值 最后,用va_end(ap),给ap初始化,保持健壮性。 example:(chenguiming) #include    <stdio.h>       #include    <ctype.h>       #include<stdlib.h>       #include    <stdarg.h>       int    average(    int    first,    ...    )      //变参数函数,C++里也有  **…表明后面有好多可变的参数。     {             int    count=0,i=first,sum=0;             va_list    maker;           //va_list    类型数据可以保存函数的所有参数,做为一个列表一样保存。Va_list即是char*表明maker是一个字符型的指针。             va_start(maker,first);    //设置列表的起始位置   **frist只是和maker在一起做参数,这并不说明maker指向frist而是指向first之后的第一个可变的参数,而frist是作为一个固定参数,因为它在…之前。这时候frist指向3。          while(i!=-1)             {             sum+=i;             count++;             i=va_arg(maker,int);//返回maker列表的当前值,并指向列表的下
阳光岛主
2019/02/19
2.1K0
同步&异步日志系统:前置知识
1、⽣产环境的产品为了保证其稳定性及安全性是不允许开发⼈员附加调试器去排查问题,可以借助日志系统来打印⼀些⽇志帮助开发⼈员解决问题
小陈在拼命
2024/12/21
1830
同步&异步日志系统:前置知识
变参函数和可变参数宏
前言:此文关于宏的内容摘抄自裸机思维公众号的"为宏证明"系列文章,本文对原文内容做了大量精简,所以难免会有晦涩难懂的地方,想要更深入了解宏的用法,还请移步到裸机思维。
AIoT-KK
2023/02/09
2.2K0
变参函数和可变参数宏
C语言打印程序行号、日期方便调试程序
平时开发C语言程序时,经常需要调试代码,C语言有一些宏,可以打印出当前的行号、文件名称、日期、时间,对程序的调试起到很大的帮助,可以快速定位问题。特别是开发单片机程序时,使用这些宏打印这些信息或者在LCD上显示程序的编译日期、时间,可以知道这个单片机上的固件是什么时候编译。帮助判断版本。
DS小龙哥
2022/06/17
2.2K0
C语言打印程序行号、日期方便调试程序
初识Linux · 日志编写
在线程池部分我们纵观全文,可以发现全文有很多很多的IO流,看起来还是差点意思的,而我们今天提到的日志,是在今后的代码编写中会经常接触,或者说在这之前,我们也接触过日志,不过我们没有注意而已,比如平常常用的电脑,强制关机什么的都会在日志里面。
_lazy
2024/12/20
1820
初识Linux · 日志编写
C++在线五子棋对战(网页版)项目:实用工具类模块代码实现
#ifndef _M_LOGGER_H_  和 #define _M_LOGGER_H_是预处理器指令,用于防止头文件被重复包含。如果头文件已经被包含了,那么这对指令将会被跳过。
二肥是只大懒蓝猫
2023/10/13
3910
C++在线五子棋对战(网页版)项目:实用工具类模块代码实现
Linux:多线程(三.POSIX信号量、生产消费模型、线程池、其他常见的锁)
信号量是一种用于进程间通信和同步的机制。它本质上是一个计数器,用于衡量系统中的资源可用数量。通过信号量,可以实现对临界资源的访问控制,确保多个进程或线程能够安全地共享资源而不发生冲突。
是Nero哦
2024/08/16
4361
Linux:多线程(三.POSIX信号量、生产消费模型、线程池、其他常见的锁)
从零开始学C++之从C到C++(一):const与#define、结构体对齐、函数重载name mangling、new/delete 等
文章主要讲述了如何利用C++语言编写一个简单的程序,该程序能够实现输入两个整数,输出它们的和。同时介绍了重载函数和带默认参数函数的使用,以及命名空间的用法。
s1mba
2017/12/28
1.3K0
【Linux】命名管道
命名管道由mkfifo创建,是一个文件,打开要用open打开 命名管道与匿名管道之间唯一的区别就是它们创建和打开的方式不同,其他基本上相同 命名管道也只能和有“血缘”的进程进行通信
s-little-monster
2025/03/04
3180
【Linux】命名管道
【C语言】va_list(可变参数处理)
        C 语言中的 va_list 类型允许函数接受可变数量的参数,这在编写需要处理不定数量参数的函数时非常有用。va_list 类型是在 stdarg.h 头文件中定义的,它允许函数处理可变数量的参数。下面我们将详细介绍 va_list 的用法以及实际应用示例。
DevKevin
2024/03/19
1.5K0
相关推荐
【c语法】##__VA_ARGS__与__VA_ARGS__
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验