首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

_VAR_ARGS_为空,为什么可以用#消除?该怎么处理

2012-03-18 
__VAR_ARGS__为空,为什么可以用##消除?看到网上有这么一句话:“#define myprintf(templt, ...) fprintf(std

__VAR_ARGS__为空,为什么可以用##消除?
看到网上有这么一句话:

#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)

这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。


##的作用是连接的作用,但这里如果想成是连接的作用,怎么会能够消除前面的逗号?

[解决办法]

探讨
看到网上有这么一句话:

#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)

这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。


##的作用是连接的作用,但这里如果想成是连接的作用,怎么会能够消除前面的逗号?

[解决办法]
#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
return 0;
}
宏展开时:
如果宏定义以#开头,不展开参数,直接替换。
故g(f(1,2))--->#f(1,2)--->"f(1,2)";
如果宏定义不以#开头,展开参数,直接替换,由外层向里层,如果碰到的是#开头的宏,不继续往里层展开,往外层展开。
由外层向里层,如果碰到的是以非#开头的宏,继续往里层走,直至最里层,开始一层层往外层展开。
故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。
PS:
##在宏中定义,是字符连接符
如a##b##c 等同于 "abc"
#在宏开头出现,是表示宏展开的方式不同
#a 等同于"a"
#abc 等同于 "abc"
复杂的:
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
char a = 'a';
cout<<g(a)<<endl; // a
cout<<g(g(a))<<endl; // a
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
printf("%s\n", g(h(f(1,2)))); // h(f(1,2))
printf("%s\n", h(g(f(1,2)))); // "f(1,2)"
printf("%s\n", h(h(f(1,2)))); // "12"
system("pause");
return 0;
}
预处理后的:(在编译选项中添加/EP /P后编译生成的.i文件)
int main()
{
char a = 'a';
cout<<"a"<<endl;
cout<<"g(a)"<<endl;
printf("%s\n", "12");
printf("%s\n", "f(1,2)");
printf("%s\n", "h(f(1,2))");
printf("%s\n", "\"f(1,2)\"");
printf("%s\n", "\"12\"");
system("pause");
return 0;
}
---------------------------------------------------
宏解析
1. ##操作符
##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号,它不能出现于宏替代表的开端和末尾。
例:
#define concat(s,t) s##t
#define AAA ABC
concat(A, AA)
将被替换成
ABC
2. 重新扫描和替换
在替换列表中的所有参数替换过之后,预处理器将对结果token序列重新扫描以便对其中的宏再次替换。
当正在替换的宏在其替换列表中发现自身时,就不再对其进行替换。今儿,在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换(防止递归)。
例:
#define ROOT AAA CCC
#define AAA ROOT
ROOT
将被替换成
ROOT CCC

[解决办法]
MSDN 没有看到你说的那个哦!


To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments. __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them. 

The C Standard specifies that at least one argument must be passed to the ellipsis, to ensure that the macro does not resolve to an expression with a trailing comma. The Visual C++ implementation will suppress a trailing comma if no arguments are passed to the ellipsis. 

Support for variadic macros was introduced in Visual C++ 2005. 

[解决办法]

探讨

#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)……


[解决办法]
LZ说的是对的;

写过类似这样的代码:

C/C++ code
#define       C_LOG(cStr, ...)            printf(cStr, ##__VA_ARGS__)如上,可以这样调用: C_LOG("the value is %d", i);也可以这样调用:C_LOG("hello!");但是如果代码改成:#define       C_LOG(cStr, ...)            printf(cStr, __VA_ARGS__)那么C_LOG("hello!");调用方式就会报错,因为__VA_ARGS__此时是没有任何参数的,所以它前面还有逗号呢而##__VA_ARGS__的作用正是可以将__VA_ARGS__表示无参数的时候把前面的逗号干掉,保持编译正确
[解决办法]
VS 下没有这个么说法,不管哪种都支持空参数。
[解决办法]
VC 下没有这个。
我估计是 GC 的特殊规定。
看看文档。
[解决办法]
探讨

VC 下没有这个。
我估计是 GC 的特殊规定。
看看文档。

[解决办法]
GCC的扩展用法
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.


带有可变参数的宏(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参数一样,这些参数不是宏的扩展。
[解决办法]

探讨
GCC的扩展用法
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 defin……

热点排行