Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntax Error in Preprocessor Macro Code

I am trying to write some code for a macro which returns the length of a string, and am attempting to implement it using BOOST_PP_WHILE. The code stems from the fact that a character at a position specified by position of the string represented by a macro argument foo may be obtained by #foo[position]. Compiling using either MSVC or Intel C++ results in similar syntax errors; if you could point out why the code is generating these syntax errors and how I would rectify code, it would be greatly appreciated. I know that the errors are caused by the code within the PREDICATE macro, but any expression I attempt to use within it barring BOOST_PP_TUPLE_ELEM results in a compile-time error.

Errors:

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

As one would expect, the line numbers are not very useful since both point to the line at which the macro MACRO_STRLEN is called.

Code

Below follows the source listing in which I attempt to implement the macro which I describe.

#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;

}
like image 481
void-pointer Avatar asked Dec 28 '22 23:12

void-pointer


2 Answers

How about this - http://codepad.org/aT7SK1Lu Its still a compile-time strlen, and would be likely much faster to compile.

#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) );
}

As to macro debug, its possible to get a preprocessor output (like gcc -E); it may be also helpful to undefine most macros, then enable them one by one to see what happens.

like image 94
Shelwien Avatar answered Jan 05 '23 14:01

Shelwien


Please forgive me if this is an irrelevant pointing out. The predicate for BOOST_PP_WHILE is evaluated while preprocess. However, if I understand correctly, MACRO_IS_NULL_IMPL determines whether the character is '\0' at compile-time(runtime?). So, I think it is difficult to accomplish the goal directly with string literal "Hello, World!".

like image 42
Ise Wisteria Avatar answered Jan 05 '23 14:01

Ise Wisteria