`
duoerbasilu
  • 浏览: 1541815 次
文章分类
社区版块
存档分类
最新评论

可变参数的宏定义

 
阅读更多

引言:

在c/c++程序设计中,经常采用printf来调试程序,但是在要发布程序时不得不从代码中删掉那些多余的printf语句,这是一项繁琐的工作。由此想到可变参数的宏,引文介绍了如何定义可变参数的宏,以及在不同C标准和不同编译器中的差别。

----------Rube

---------------------------------------------------------------------------------------------------------------------
声明:
此文为原创翻译,欢迎转载,转载请保留如下信息
作者:聂飞(afreez)
联系方式:afreez@sina.com (欢迎与作者交流)
初次发布时间:2006-06-03
不经本人同意,不得用语商业或赢利性质目的,否则,作者有权追究相关责任!
---------------------------------------------------------------------------------------------------------------
带有可变参数的宏(Macros with a Variable Number of Arguments

1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

这里,‘’指可变参数。这类宏在被调用时,它(这里指‘’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。

GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:

#define debug(format, args...) fprintf (stderr, format, args)

这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

debug ("A message")

GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的‘##’操作。书写格式为:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,‘##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。


GCC4.1.1.pdf 236页

5.14 Macros with a Variable Number of Arguments.

In the ISO C standard of 1999, a macro can be declared to accept a variable number of

arguments much as a function can. The syntax for defining the macro is similar to that of

a function. Here is an example:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

Here ‘...’ is a variable argument. In the invocation of such a macro, it represents the

zero or more tokens until the closing parenthesis that ends the invocation, including any

commas. This set of tokens replaces the identifier __VA_ARGS__ in the macro body wherever

it appears. See the CPP manual for more information.

GCC has long supported variadic macros, and used a different syntax that allowed you

to give a name to the variable arguments just like any other argument. Here is an example:

#define debug(format, args...) fprintf (stderr, format, args)

This is in all ways equivalent to the ISO C example above, but arguably more readable

and descriptive.

GNU CPP has two further variadic macro extensions, and permits them to be used with

either of the above forms of macro definition.

In standard C, you are not allowed to leave the variable argument out entirely; but you

are allowed to pass an empty argument. For example, this invocation is invalid in ISO C,

because there is no comma after the string:

debug ("A message")

GNU CPP permits you to completely omit the variable arguments in this way. In the

above examples, the compiler would complain, though since the expansion of the macro still

has the extra comma after the format string.

To help solve this problem, CPP behaves specially for variable arguments used with the

token paste operator, ‘##’. If instead you write

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

and if the variable arguments are omitted or empty, the ‘##’ operator causes the preprocessor

to remove the comma before it. If you do provide some variable arguments in

your macro invocation, GNU CPP does not complain about the paste operation and instead

places the variable arguments after the comma. Just like any other pasted macro argument,

these arguments are not macro expanded.

分享到:
评论

相关推荐

    C51可变参数讲解.pdf

    C51可变参数函数允许程序员设计能接受不定数量参数的函数,这在C语言中是通过头文件stdarg.h提供的宏实现的。stdarg.h在Keil C51环境中也提供了对可变参数函数的支持,可以让嵌入式开发人员灵活地编写函数,以处理...

    C/C++宏定义的可变参数详细解析

    1. 可变参数宏的定义: 在C99中,可以使用`...`来表示可变参数列表。当宏被调用时,这些可变参数会被一系列的参数值所替代。在宏定义中,可以使用`__VA_ARGS__`来引用这些可变参数。例如: ```c #define debug...

    c语言中可变参数va宏的使用

    可变参数宏在C语言中提供了一种灵活的方式来处理不定数量和类型的参数。通过对`va_list`、`va_start`、`va_arg`和`va_end`的理解与运用,开发者可以在嵌入式系统以及其他应用场景中更好地管理动态数据。这些宏不仅...

    C、C++中变参数宏

    可变参数宏是 C 语言中的一种特殊宏定义,允许宏定义中包含可变数量的参数。这种宏定义使用省略号(...)来表示可变参数。例如: ```c #define PR(...) printf(__VA_ARGS__) ``` 在上面的宏定义中,PR 是一个宏名,....

    c 语言中的宏,井号,可变参数.doc

    在某些情况下,宏可能只接收一个参数,如格式字符串,但仍然需要遵循可变参数宏的调用约定。例如: ```c myprintf("Error!"); ``` 上述调用应该被解释为: ```c fprintf(stderr, "Error!"); ``` 然而,按照C99的...

    C语言宏定义详解

    __VA_ARGS__是在宏定义中用作可变参数的占位符,它将被宏调用时的实际参数替换。 5. 宏定义中的字符串化和粘合操作 在宏定义中,使用`#`操作符可以对宏参数进行字符串化操作,即将参数转换为字符串形式;使用`##`...

    C语言中的可变参数

    在C语言中,可变参数的实现基于调用约定(calling convention),通常涉及到两个关键函数:`va_start`、`va_end` 和一个宏 `va_list`。`va_list` 是一个类型定义,用于存储可变参数列表的指针;`va_start` 用于初始...

    c#调用c++的可变参数

    这些宏提供了在运行时动态访问可变参数列表的能力。 3. **C#处理C++可变参数**:然而,C#本身并不支持可变参数,因此不能直接映射到C++的可变参数函数。为了调用这样的函数,我们需要一些技巧。一种常见方法是创建...

    C语言可变参数及printf函数的实现

    这些宏提供了访问和遍历可变参数列表的方法。`va_start`初始化`va_list`,`va_arg`用于获取下一个参数,而`va_end`在使用完所有参数后结束访问。 #### 结论 通过以上分析,我们可以看到,尽管可变参数函数在编写时...

    C语言中可变参数的用法

    这些宏定义在`stdarg.h`头文件中,因此编写可变参数函数时需要包含此头文件。 #### 宏定义解析 1. **`va_start`**: 初始化可变参数列表的迭代器。 - `void va_start(va_list arg_ptr, prev_param);` - 参数: -...

    C语言可变参数

    C语言通过一组宏和一个类型来实现可变参数。这三个宏分别是`va_start`、`va_end`和`va_arg`,以及一个类型`va_list`。 - `va_start(ap, paramN)`:初始化可变参数列表。`ap`是用于存储参数列表的变量,`paramN`是...

    C语言中一些可变参数的用法

    本文讨论了C语言中可变参数的用法,包括如何写一个简单的可变参数的C函数,如何使用可变参数宏va_start、va_arg和va_end,以及可变参数在编译器中的处理。 一、写一个简单的可变参数的C函数 在C语言中,某些函数...

    C/C++定义可变参数函数,演示程序

    可变参数函数的核心是`stdarg.h`库,它提供了一些宏和类型,帮助我们在函数内部处理可变数量的参数。首先,我们需要包含这个头文件: ```cpp #include ``` 在C++中,为了定义可变参数函数,我们通常会有一个固定...

    C以及Java中可变参数列表函数定义方法

    本文将探讨一个共同的话题——如何在C和Java中定义可变参数列表的函数。可变参数列表,也称为不定参数或可变参数,允许函数接受不同数量的参数,增加了代码的灵活性。 在C语言中,可变参数列表的实现依赖于`stdarg....

    巧用C语言宏定义实现自动注释调试代码

    这里的`__VA_ARGS__`是可变参数列表,允许传递任意数量的参数。`DEBUG_PRINT`宏在调试模式下会打印出指定格式的调试信息,而在非调试模式下则不会有任何输出。 在Linux环境中,我们可以通过`gcc`编译器的`-D`选项来...

    C语言中可变参数的用法.doc

    在C语言中,可变参数的使用是一种灵活的特性,允许函数接受不同数量或类型的参数。这在处理如`printf`等需要动态参数列表的函数时非常有用。`printf`函数的定义允许用户根据需要传递任意数量的格式化参数。 在C语言...

    C语言可变参数的使用

    首先,C语言中的可变参数是通过`stdarg.h`头文件提供的宏和类型来实现的。这个头文件包含了一些关键的函数和类型定义,如`va_list`、`va_start`、`va_arg`和`va_end`,它们是处理可变参数的关键。 1. `va_list`:这...

    c/C++可变参数函数的参数传递机制剖析

    3. **可变参数类型未知**:在定义函数时,可变参数的具体类型未知。因此,在函数体内需要使用 `va_arg` 宏来逐个读取这些参数,并且每次调用 `va_arg` 时都需要指定参数的类型。 #### 总结 通过以上分析,我们可以...

    C语言宏定义##连接符和#符的使用

    C99引入了可变参数宏,其中`#`和`##`可以用来处理更复杂的参数组合: ```c #define myprintf(format, ...) fprintf(stderr, format, ##__VA_ARGS__) myprintf("Error!%d/n", 123); ``` 这里,`##__VA_ARGS__`用于...

    用C语言实现参数个数可变的函数

    这些宏定义在stdarg.h头文件中,它们允许函数访问可变数量的参数,这种处理方式通常被称为可变参数列表或可变参数宏。 在C语言中,实现参数个数可变的函数主要有两种形式,分别是ANSI标准形式和与UNIX System V兼容...

Global site tag (gtag.js) - Google Analytics