Синтаксическая ошибка в макросе препроцессора - PullRequest
4 голосов
/ 21 марта 2011

Я пытаюсь написать код для макроса, который возвращает длину строки, и пытаюсь реализовать его с помощью BOOST_PP_WHILE. Код проистекает из того факта, что символ в позиции, заданной position строки, представленной макро аргументом foo, может быть получен с помощью #foo[position]. Компиляция с использованием MSVC или Intel C ++ приводит к аналогичным синтаксическим ошибкам; Если бы вы могли указать, почему код генерирует эти синтаксические ошибки и как я исправил бы код, это было бы очень полезно. Я знаю, что ошибки вызваны кодом в макросе PREDICATE, но любое выражение, которое я пытаюсь использовать в нем, за исключением BOOST_PP_TUPLE_ELEM, приводит к ошибке во время компиляции.

Ошибка:

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 ]

3 голосов
/ 21 марта 2011

Как насчет этого - 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);также может быть полезно отменить определение большинства макросов, а затем включить их один за другим, чтобы увидеть, что происходит.

3 голосов
/ 21 марта 2011

Это не сработает, и по простой причине: препроцессор не предназначен для работы с литералами.

Препроцессор знает только о «токенах», он может их скомпоновать, он может преобразовать один встроковый литерал, и он может управлять заменами макросов, но это все.

Здесь условие остановки цикла (использование [] и ==) в лучшем случае может выполняться компилятором(и, скорее всего, во время выполнения), поэтому не подходит для BOOST_PP_WHILE.

На самом деле вы можете использовать компилятор, чтобы получить количество элементов в массиве (здесь массив символов):

Например, используя sizeof: sizeof(array)/sizeof(array[0]).Это можно абстрагировать в макросе, однако это не может стать «обычной» функцией, поскольку массивы нельзя передавать «обычным» функциям, только указатели (где вы потеряли размер информации).

Вы можететакже используйте функцию шаблона:

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

(на самом деле это работает для любого массива с постоянным размером)

Но, для вашей собственной проблемы, вам будет приятно узнать, что большинство компиляторовиметь встроенную реализацию strlen для констант, которая вычисляется во время компиляции.

3 голосов
/ 21 марта 2011

Пожалуйста, прости меня, если это неуместное указание.Предикат для BOOST_PP_WHILE оценивается во время предварительной обработки.Однако, если я правильно понимаю, MACRO_IS_NULL_IMPL определяет, является ли символ '\0' во время компиляции (во время выполнения?).Поэтому я думаю, что трудно достичь цели напрямую с помощью строкового литерала "Hello, World!".

1 голос
/ 21 марта 2011

Интересно, должно ли это быть что-то вроде этого:

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

Но это не оценка времени компиляции, даже если она обычно оптимизируется до константы.

...