LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: Illidan

[C] 一个函数声明中带了两个##,什么意思?

[复制链接]
发表于 2005-5-20 10:11:17 | 显示全部楼层
看我在5楼的那个例子就知道了。
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:12:46 | 显示全部楼层
Post by Tetris
看我在5楼的那个例子就知道了。

你的意思是这个只在GCC里有????
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:22:27 | 显示全部楼层
##不是gcc才有,在一般情况下用于作为宏里的参数和一个字串的连接,也就是你在2楼说的那种。在gcc里,##args用于做为不定参数,在C99支持不定参数的宏,但用的符号是__VA_ARGS__,作用与gcc中的##args完全一样。
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:24:01 | 显示全部楼层
Post by Tetris
不是吧?这个很明显是个不定参数的宏里调用一个不定参数的函数(cpLog_impl_)啊。
cpLog_impl_ (priority__, __FILE__, __LINE__, fmt__ , ##args__);
看函数的第4个参数fmt(format)就知道了,cpLog_impl_是一个和sprintf有点像的函数,可能它还会再调用vsprintf。

你说的不错,但你没有理解我的意思。
比如说有这样一个宏定义:
#define err_log(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
这就要求可变参数中到少有一个参数。如果我想这样用
err_log("open file failed\n");
那么经过宏扩展后,就会变成:
fprintf(stderr, "open file failed\n", );
在fprintf的参数列表中最后的逗号后面没有参数。在编译时就会报错。
如果定义成
#define err_log(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
在扩展后就会变成:
fprintf(stderr, "open file failed\n");
这样就不会报错。

这样做可以给错误信息的输出带来一定的灵活性。
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:35:31 | 显示全部楼层
不过话说回来,楼主没有给出完整的宏定义,很有可能我们都说错了。
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:37:32 | 显示全部楼层
我的例子有一点问题,gcc和C99的用法不完全一样,下面用gcc和c99分别写一个例子:
gcc版,注意"..."是和不定参数连在一起的,不定参数的名字任意,而不一定是##args,我前面说错了:

  1. #define perr_exit(format, args...) \
  2. do { \
  3.     fprintf(stderr, format, ##args); \
  4.     exit(1); \
  5. } while (0)

复制代码


C99版,一般我都有这样方式,在宏的参数列表中无需写明不定参数的名字,写"..."就可以了:

  1. #define perr_exit(format, ...) \
  2. do { \
  3.     fprintf(stderr, format, ##__VA_ARGS__); \
  4.     exit(1); \
  5. } while (0)

复制代码
回复 支持 反对

使用道具 举报

发表于 2005-5-20 10:42:11 | 显示全部楼层
Post by kj501
你说的不错,但你没有理解我的意思。
比如说有这样一个宏定义:
#define err_log(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
这就要求可变参数中到少有一个参数。如果我想这样用
err_log("open file failed\n");
那么经过宏扩展后,就会变成:
fprintf(stderr, "open file failed\n", );
在fprintf的参数列表中最后的逗号后面没有参数。在编译时就会报错。
如果定义成
#define err_log(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
在扩展后就会变成:
fprintf(stderr, "open file failed\n");
这样就不会报错。

这样做可以给错误信息的输出带来一定的灵活性。


晕了,版主厉害。我的例子中应该用##__VA_ARGS__而不是__VA_ARGS__
以前没有注意到__VA_ARGS__不可以为空。
回复 支持 反对

使用道具 举报

发表于 2005-5-20 11:16:11 | 显示全部楼层
Post by Tetris


  1. #define perr_exit(format, args...) \
  2. do { \
  3.     fprintf(stderr, format, ##args); \
  4.     exit(1); \
  5. } while (0)

复制代码


请问在上面代码do-while循环只作一次,有什么作用?
回复 支持 反对

使用道具 举报

发表于 2005-5-20 11:29:27 | 显示全部楼层
如果不加在do {} while (0)里,则下面的使用会出错:
if (...)
    perr_exit(...);
else
    ....
因为被展开成:
if (...)
{
    fprintf(stderr, ...);
    exit(1);
};
else
    ...
回复 支持 反对

使用道具 举报

发表于 2005-5-20 11:53:57 | 显示全部楼层
明白了。因为把if和else语句分开了,所以程序出错。
谢谢。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表