预处理器宏代码中的语法错误

时间:2011-03-21 08:41:59

标签: c++ boost c-preprocessor metaprogramming

我正在尝试为宏返回字符串长度的代码,并尝试使用BOOST_PP_WHILE实现它。该代码源于这样一个事实:position可以获得由宏参数foo表示的字符串的#foo[position]指定的位置处的字符。使用MSVC或Intel C ++进行编译会导致类似的语法错误;如果您能指出为什么代码会产生这些语法错误以及如何纠正代码,那将非常感激。 我知道错误是由PREDICATE宏中的代码引起的,但我尝试在其中使用的任何表达式BOOST_PP_TUPLE_ELEM都会导致编译时错误。 < / p>

错误:

prog.cpp:47:1: error: pasting "BOOST_PP_BOOL_" and ""\"Hello, World!\""" does not give a valid preprocessing token
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:47: error: ‘BOOST_PP_TUPLE_ELEM_2_1’ was not declared in this scope

正如人们所预料的那样,行号不是很有用,因为它们都指向调用宏MACRO_STRLEN的行。

代码

下面是我尝试实现我描述的宏的源列表。

#include <boost/preprocessor/arithmetic/dec.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/control/while.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <cstdio>

#define TEST_STRING0 "Hello, World!"

#define MACRO_IS_NULL_IMPL(x, position) \
    #x[position] == '\0'

#define MACRO_IS_NULL(x, position) \
    MACRO_IS_NULL_IMPL(x, position)

#define PREDICATE_D(string, position) \
    MACRO_IS_NULL(string, position)

#define PREDICATE(n, state) \
    PREDICATE_D( \
        BOOST_PP_TUPLE_ELEM(2, 0, state), \
        BOOST_PP_TUPLE_ELEM(2, 1, state) \
    )

#define OPERATION_D(string, position) \
    ( \
        string, \
        BOOST_PP_INC(position) \
    )

#define OPERATION(d, state) \
    OPERATION_D( \
        BOOST_PP_TUPLE_ELEM(2, 0, state), \
        BOOST_PP_TUPLE_ELEM(2, 1, state) \
    )

#define MACRO_STRLEN_IMPL(string) \
    BOOST_PP_TUPLE_ELEM( \
        2, 1, BOOST_PP_WHILE(PREDICATE, OPERATION, (string, 0)) \
    )

#define MACRO_STRLEN(string) \
    MACRO_STRLEN_IMPL(string)

int main(int argc, char ** argv) {

    printf("String length: %d.\n", MACRO_STRLEN(TEST_STRING0));
    return 0;

}

4 个答案:

答案 0 :(得分:3)

如果这是一个无关紧要的指示,请原谅我。 在预处理时评估BOOST_PP_WHILE的谓词。 但是,如果我理解正确,MACRO_IS_NULL_IMPL确定是否 编译时字符是'\0'(运行时?)。 所以,我认为用字符串直接完成目标很困难 文字"Hello, World!"

答案 1 :(得分:3)

这个怎么样 - http://codepad.org/aT7SK1Lu 它仍然是一个编译时strlen,并且编译速度可能会快得多。

#include <stdio.h>
#include <string.h>

#define TEST_STRING "Hello, World!"

template <int N> struct xtmp2 { typedef char (&t)[N]; };
template< class T, int N > typename xtmp2<N>::t xlen( T (&)[N] );
#define STRLEN(x) (sizeof(xlen(x))-1)

int main( void ) {

  printf( "strlen(\"%s\") = %i %i\n", TEST_STRING, STRLEN(TEST_STRING), strlen(TEST_STRING) );
}

对于宏调试,它可以获得预处理器输出(如gcc -E); 取消定义大多数宏,然后逐个启用它们也可能有帮助 看看会发生什么。

答案 2 :(得分:3)

它不起作用,原因很简单:预处理器并不意味着处理文字。

预处理器只知道“令牌”,它可以安排它们,它可以将一个转换为字符串文字,它可以操作宏替换,但就是这样。

这里,停止循环的条件(使用[]==)最多可以由编译器执行(并且最有可能在运行时),因此不适合{ {1}}。

实际上,你可以使用编译器来获取数组元素的数量(这里是一个字符数组):

例如,使用BOOST_PP_WHILEsizeof。这可以在宏中抽象,但它不能成为“常规”函数,因为数组不能传递给“常规”函数,只能传递给指针(你丢失了信息大小)。

您还可以使用模板功能:

sizeof(array)/sizeof(array[0])

(这实际上适用于任何具有恒定大小的数组)

但是,对于您自己的问题,您会很高兴地知道大多数编译器都有针对在编译时求值的常量的内置template <typename T, size_t N> size_t size(T (&)[N]) { return N; } 实现。

答案 3 :(得分:1)

我想知道它是否应该是这样的:

#include <stdio.h>
#include <string.h>

#define TEST_STRING "Hello, World!"

#define STRLEN(x)    (x[0]==0)?0:TEST_01(x,1)
#define TEST_01(x,y) (x[y]==0)?y:TEST_02(x,y+1)
#define TEST_02(x,y) (x[y]==0)?y:TEST_03(x,y+1)
#define TEST_03(x,y) (x[y]==0)?y:TEST_04(x,y+1)
#define TEST_04(x,y) (x[y]==0)?y:TEST_05(x,y+1)
#define TEST_05(x,y) (x[y]==0)?y:TEST_06(x,y+1)
#define TEST_06(x,y) (x[y]==0)?y:TEST_07(x,y+1)
#define TEST_07(x,y) (x[y]==0)?y:TEST_08(x,y+1)
#define TEST_08(x,y) (x[y]==0)?y:TEST_09(x,y+1)
#define TEST_09(x,y) (x[y]==0)?y:TEST_10(x,y+1)
#define TEST_10(x,y) (x[y]==0)?y:TEST_11(x,y+1)
#define TEST_11(x,y) (x[y]==0)?y:TEST_12(x,y+1)
#define TEST_12(x,y) (x[y]==0)?y:TEST_13(x,y+1)
#define TEST_13(x,y) (x[y]==0)?y:TEST_14(x,y+1)
#define TEST_14(x,y) (x[y]==0)?y:TEST_15(x,y+1)
#define TEST_15(x,y) (x[y]==0)?y:TEST_16(x,y+1)
#define TEST_16(x,y) (x[y]==0)?y:TEST_17(x,y+1)
#define TEST_17(x,y) (x[y]==0)?y:TEST_18(x,y+1)
#define TEST_18(x,y) (x[y]==0)?y:TEST_19(x,y+1)
#define TEST_19(x,y) (x[y]==0)?y:-1

int main( void ) {
  printf( "strlen(\"%s\") = %i %i\n", TEST_STRING, STRLEN(TEST_STRING), strlen(TEST_STRING) );
}

但这不是编译时评估,即使通常也是如此 优化为常数。