2009-07-28 3 views
2

Я взломал программу, которая сама создает программы моделирования в C. Пользователь определяет дизайн верхнего уровня, и эти программы вставляют небольшие C-фрагменты и клей-код helluvalot (несколько тысяч строк).Избегайте повторных замещений в предварительном процессоре C

Это делает местное именование по #defines:

#define x local_x 
#define vx local_vx 
/* user code that uses x, ex */ 
vx = x/2 
#undef vx 
#undef x 

Это примерно расширяется до следующего:

local_vx = local_x/2 

НО если использовать структуры для local_* -variables (оптимизировать на необходимости проходить 11 переменных для каждой отдельной функции ...):

#define x local->position.x 
#define vx local->velocity.x 
vx = x/2 
#undef vx 
#undef x 

Wh ич получает расширен до

local->velocity.x = local->position.x 

И - вот проблема - x в скорости становится расширена снова:

local->velocity.local->position.x = local->position.x 

Я не могу поставить скобки вокруг, так как он не имеет права назначать на переменные ((x) = 1 являются незаконными C, к сожалению ...). Любые намеки?

Обновление: Сгенерированное моделирование обычно весит от 15 до 20 000 LOC, и моделирование приблизительно на десять лет должно быть обратно совместимо с. Увы, просто переименование чего-то совсем не просто ... Поскольку, похоже, нет простого способа обойти эту конкретную проблему без какой-либо крупной реорганизации (я думал, что пропустил некоторые особенности C pre-processor), я решил сделать шаг назад и посмотреть, какие у меня есть другие варианты.

+0

Препокорсор C и C++ не рекурсивен. – 2009-07-28 17:00:34

+0

Спасибо! Изменено название для соответствия. –

+0

Было много предложений по изменению семантики локального положения (имена членов или создания массива), но должна ли поддерживаться совместимость? – bdonlan

ответ

3

Это на самом деле не является рекурсивным, что происходит в том, что

#define x local->position.x 
#define vx local->velocity.x 

расширяется до

#define x local->position.x 
#define vx local->velocity.local->position.x 

, который затем включен в заявление позже. Я не уверен, как вы хотите обойти это, но я бы сказал, что изменить имена переменных/# определить имена, чтобы быть чем-то более уникальным, чтобы этого избежать.

+0

Да, меняйте «x» на «px» – Nosredna

+0

Черт! Это оно! Слишком много изменений в именах переменных на самом деле не является вариантом, так как существует ~ 10 лет письменной симуляции, которая должна быть совместима ... –

+0

Я попытался переупорядочить '# define', поэтому' x' является последний, но затем я просто ударил проблему, которую я описываю в исходном вопросе. –

0

какой компилятор вы используете Morten? Первым шагом может быть проверка справочного руководства компилятора, чтобы узнать, есть ли какие-либо параметры, которые вы можете изменить в отношении уровней предварительной обработки или рекурсивной подстановки.

+0

Я не думаю, что в препроцессоре C есть рекурсивная замена. – Nosredna

+0

В настоящее время я использую 'gcc', но я должен быть совместим с C-компиляторами из Microsoft и Intel. –

+0

Носредна - да, ты прав, моя ошибка. – dls

0

Если определения должны быть x и vx (с не так уж велики, как вы могли заметить), один из способов решить это - изменить член структуры/класса local->velocity.x на local->velocity.x_ (или что-то подобное).

1

Если вы используете C++, вы можете рассмотреть возможность использования ссылок вместо:

int &x = local->position.x; 

Поскольку вы пишете генератор кода, это не должно быть слишком трудно, чтобы убедиться, что они существуют для право сфера:

{ 
    int &x = local->position.x; 
    int &y = local->position.y; 
    int &vx = local->velocity.x; 
    int &vy = local->velocity.y; 
    { 
#line user.input 1234 
     // user code 
#line output.c 4567 
    } 
} 

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

Если вы не используете C++, рассмотреть возможность делать - самый большой источник несовместимости между C и C++ будет отсутствие неявного пустого указателя бросает, который я подозреваю, редко встречается в ваших входных фрагментах ...

2

Просто сумасшедшая идея, но как насчет вместо этого

#define x local->position.x 
#define vx local->velocity.x 
vx = x/2 
#undef vx 
#undef x 

Почему бы просто не назвать это что-то другое? как

#define x local->position.val 
#define vx local->velocity.val 
vx = x/2 
#undef vx 
#undef x 

Вот пример программы, которая прекрасно работает под GCC 4.3.2

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     unsigned char val; 
    } Value; 

    typedef struct 
    { 
     Value position; 
     Value velocity; 
    } Holder; 

    Holder temp; 
    Holder* local = &temp; 
    #define x local->position.val 
    #define vx local->velocity.val 
    vx = x/2; 
    #undef vx 
    #undef x 

    return 0; 
} 
0

Я бы сделать position и velocity массивы. Тогда ваши определения будут выглядеть так:

#define x local->position[0] 
#define vx local->velocity[0] 

, так что больше нет возможности для повторного расширения макросов.

Переименование элемента структуры на что-то отличное от x также будет работать, но на самом деле я нахожу, что массивы имеют больше смысла здесь.

0

Предполагая, что:

  • Вы не можете изменить имена элементов структуры, и
  • Вы не можете изменить имена Определяет

Тогда один из способов является создать теневой тип структуры. Произнесите положения и скорости члены этого типа:

struct vector { 
    double x; 
    double y; 
}; 

Затем вы создаете тип тени, который идентичен для названия членов, за исключением, и союз, содержащий как обойти Aliasing правила:

struct _vector { 
    double _x; 
    double _y; 
}; 

union _u_vector { 
    struct vector _v1; 
    struct _vector _v2; 
}; 

и тогда ваши определяет может быть:

#define x ((struct _vector *)(union _u_vector *)(&local->position))->_x 
#define vx ((struct _vector *)(union _u_vector *)(&local->velocity))->_x 

Это немного рубить, но вы очень ограничены. Обратите внимание на то, что шаблон элемента() будет оптимизирован до struct.member, так что у него не будет никаких дополнительных затрат времени выполнения.

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

0

Извлеките #define и смените генератор кода, чтобы сгенерировать соответствующий код. Вы не описали описанные вами #define, которые, похоже, не покупают вам ничего, кроме немного более коротких идентификаторов (или есть что-то важное, что вы не упомянули). Разверните переменные в генераторе кода, а не в препроцессоре C.

Что касается совместимости с имитациями более 10 лет, я бы надеялся, что исходные файлы ввода для генератора кода были сохранены, поэтому вы можете запустить его снова, если необходимо (или даже лучше, что генерация кода является частью его сборки обработать). Если это какой-то мастер интерактивного создания кода и/или разработчики, который редактирует сгенерированный код, вы уже находитесь в мире обид, и мне нужно задаться вопросом, как вы делаете какие-либо существенные изменения в сгенерированном коде в первом место (вручную? сценарий после обработки?).