Typecast可变宏中的所有参数

时间:2014-11-20 13:24:16

标签: c arguments c-preprocessor variadic-macros

我想用sscanf来解析长字符串。
要解析的数据将存储在其成员都是time_t类型的结构中 不幸的是,没有任何格式字符串可以标记time_t所以我只是将所有time_t *个参数强制转换为unsigned long long *,因为它是一个包含大量参数的非常长的字符串,逐个类型化每个参数只会弄乱我的编辑器屏幕..

所以,我创建了一个宏来简化这个:

#define typecast(type, ...) (type) __VA_ARGS__

我这样调用它:

sscanf(string, PARSE_STRING,
    typecast(unsigned long long *, /* my arguments */));

我虽然会扩展到:

sscanf(string, PARSE_STRING,
    (unsigned long long *) /* arg1 */, (unsigned long long *) /* arg2 */, /* and so on */);

但在用gcc -E进行检查后,我发现它扩展到了这个:

sscanf(string, PARSE_STRING,
    (unsigned long long *) /* arg1 */, /* arg2 */, /* and so on */));

如何使用可变参数函数实现所需的扩展功能?

2 个答案:

答案 0 :(得分:0)

我已经看到C预处理器代码循环使用可变参数宏的参数,我不希望它在我的代码中。但是,在您的情况下,您可以采取以下解决方案。我提出的宏最多可以处理4个参数,你肯定可以将它扩展到任何常量。

#define typecast4(type, a1, a2, a3, a4, ...) ((type)a1), ((type)a2), ((type)a3), ((type)a4)
#define typecast(type, ...) typecast4(type, __VA_ARGS__, NULL, NULL, NULL, NULL)

此特定解决方案始终生成4个参数。请注意,在您的情况下,这无关紧要,因为scanf接受并安全地忽略输入格式之外的任何参数。因此,以下代码编译:

int main() {
  time_t x,y;
  scanf("%lld, %lld", typecast(long long *, &x, &y));
  ...
}

但是,我担心从time_t *long long *的演员阵容。它无处写,time_t必须由long long表示。如果它在某个平台上由int表示,则之前的代码将是错误的。扫描您的值的正确方法如下:

int main() {
  time_t x,y;
  long long lx, ly;
  scanf("%lld, %lld", &lx, &ly);
  x = lx;
  y = ly;
  ...
}

更正确,不需要任何可变参数宏。

答案 1 :(得分:-1)

使用boost

#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define CAMMA(r, data, i, elem) BOOST_PP_COMMA_IF(i)elem
#define CAST(r, data, elem) (data)elem
#define typecast(type, ...) BOOST_PP_SEQ_FOR_EACH_I(CAMMA, , BOOST_PP_SEQ_TRANSFORM(CAST, type, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))