Syntax error in preprocessor macro code

I am trying to write code for a macro that returns the length of a string, and I am trying to implement it with BOOST_PP_WHILE. The code stems from the fact that the character at the position given by the position string represented by the macro argument foo can be obtained using #foo[position] . Compilation using MSVC or Intel C ++ leads to similar syntax errors; if you could indicate why the code generates these syntax errors and how I will correct the code, it would be very useful. I know that errors are caused by code inside the PREDICATE macro, but any expression that I try to use in it that prohibits BOOST_PP_TUPLE_ELEM leads to a compile-time error.

Error:

 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 you would expect, line numbers are not very useful, since both point to the line on which the MACRO_STRLEN macro is MACRO_STRLEN .

code

The following is a list of sources in which I am trying to implement the macro that I am describing.

 #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
source share
4 answers

How about this - http://codepad.org/aT7SK1Lu Its still a strlen compilation and will most likely be 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 for macro debugging, you can get the output of the preprocessor (for example, gcc -E); It may also be useful to identify most macros, then include them one by one so that what happens.

+3
source

Please forgive me if it does not matter. The predicate for BOOST_PP_WHILE is evaluated during the preprocess. However, if I understand correctly, MACRO_IS_NULL_IMPL determines the character '\0' at compile time (runtime?). So, I think that to execute the task directly using the string literally "Hello, World!" .

+3
source

This will not work for a simple reason: the preprocessor is not designed to handle literals.

The preprocessor only knows about the “tokens”, it can connect them, it can convert it to a string literal, and it can work with macro replacements, but what is it.

Here the condition for stopping the loop (using [] and == ) can, at best, be met by the compiler (and most likely at runtime), therefore it is not suitable for BOOST_PP_WHILE .

You can use the compiler to get the number of array elements (here is an array of characters):

For example, using sizeof : sizeof(array)/sizeof(array[0]) . This can be abstracted in a macro, however, it cannot become a “regular” function, since arrays cannot be passed to “regular” functions, only pointers (where you lost the size of the information).

You can also use the template function:

 template <typename T, size_t N> size_t size(T (&)[N]) { return N; } 

(this really works on any array with constant size)

But for your own problem, you will be pleased to know that most compilers have a built-in strlen implementation for constants, which is evaluated at compile time.

+3
source

I wonder if it was something like this:

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

But this is not an estimate of compilation time, although usually it will be optimized to a constant.

+1
source

Source: https://habr.com/ru/post/1344569/


All Articles