Макрос и функция с тем же именем

У меня есть следующий код

#define myfunc(a,b) myfunc(do_a(a), do_b(b))

void myfunc(int a, int b)
{
  do_blah(a,b);
}
int main()
{
    int x = 6, y = 7;
    myfunc(x,y);

    return 0;
}

Я хочу, чтобы препроцессор расширял функцию myfunc только при вызове. Требуемый код после предварительной обработки выглядит так:

void myfunc(int a, int b)
{
  do_blah(a,b);
}
int main()
{
    int x = 6, y = 7;
    myfunc(do_a(x),do_b(y));

    return 0;
}

Проблема в том, что определение функции расширяется так же

void myfunc(do_a(int a), do_b(int b))
{
  do_blah(a,b);
}

Есть ли способ заставить макрос разворачиваться только в том случае, если мы расширяем вызов функции? Я пробовал много решений, и это кажется невозможным, но я надеюсь, что кто-то видел такую ​​ситуацию ...

ПРИМЕЧАНИЕ: пожалуйста, не говорите мне переименовывать имена макросов или функций: D

Update1: Спасибо за помощь. Но я могу изменить только определение макроса, я не могу изменить его положение и не могу изменить реализацию функции.


person Yousf    schedule 23.12.2009    source источник


Ответы (5)


Используйте (), чтобы препроцессор не расширял определение функции:

#include <stdio.h>

#define myfunc(a, b) myfunc(do_a(a), do_b(b))
/* if you have a preprocessor that may be non-standard
 * and enter a loop for the previous definition, define
 * myfunc with an extra set of parenthesis:
#define myfunc(a, b) (myfunc)(do_a(a), do_b(b))
 ******** */

int (myfunc)(int a, int b) /* myfunc does not get expanded here */
{
    printf("a=%d; b=%d\n", a, b);
    return 0;
}

int do_a(int a)
{
    return a * 2;
}

int do_b(int b)
{
    return b - 5;
}

int main(void)
{
    myfunc(4, 0);
    return 0;
}
person pmg    schedule 23.12.2009
comment
Я думаю, что некоторые препроцессоры могут возразить против рекурсивного использования формы myfunc (xxx, xxx). Я бы сделал #define myfunc (a, b) (myfunc) (do_a (a), do_b (b)) int (myfunc) (int a, int b) & c - person Tim Schaeffer; 23.12.2009
comment
Хорошее замечание, Тим, спасибо! Но я думаю, безопасно предположить, что препроцессор никогда не войдет в рекурсивный цикл (см. Стандарт 6.10.3.4/2 ... если какие-либо вложенные замены обнаруживают имя заменяемого макроса, оно не заменяется ...). - person pmg; 23.12.2009
comment
Если вы можете изменить функцию так, чтобы вокруг ее имени поместили (), почему вы не можете изменить имя функции? - person Pete Kirkham; 24.12.2009
comment
Я тоже об этом думал, но у меня не хватило смелости задать вопрос напрямую :) - person pmg; 24.12.2009
comment
Чтобы изменить название функции, вам необходимо - получить одобрение всех менеджеров - обновить все документы - повторно запустить тестовые примеры - person Yousf; 24.12.2009

Я вижу три возможных решения:

  • определите свой макрос после определения функции.

  • перед определением функции определите do_a() и do_b(), чтобы они возвращали свой аргумент, и переопределите их по вашему желанию после определения функции

  • выполнить do_a() и do_b() внутри функции:

    void myfunc(int a, int b)
    {
        do_blah(do_a(a),do_b(b));
    }
    

Я сильно предпочитаю последнее.

person mouviciel    schedule 23.12.2009

Определите макрос после определения функции.

void myfunc(int a, int b)
{
  do_blah(a,b);
}

#define myfunc(a,b) myfunc(do_a(a), do_b(b))

int main()
{
    int x = 6, y = 7;
    myfunc(x,y);

    return 0;
}
person Gunther Piez    schedule 23.12.2009

Определите макрос после определения функции.

В качестве альтернативы используйте такой шаблон:

#define myfunc_macro(a,b) myfunc(do_a(a), do_b(b))
#define myfunc(a,b) myfunc_macro(a,b)

.
.

#undef myfunc
void myfunc(int a, int b)
{
  do_blah(a,b);
}
#define myfunc(a,b) myfunc_macro(a,b)

.
.

int main()
{
    int x = 6, y = 7;
    myfunc(x,y);

    return 0;
}
person moonshadow    schedule 23.12.2009

Почему нельзя изменить исходный код? В худшем случае, если вам нужно сохранить исходную версию, запустите patch на нем, чтобы создать временный файл, в котором функция переименована, и построить его оттуда.

person Pete Kirkham    schedule 23.12.2009
comment
это унаследованный код .. изменение имени функции или макроса не вариант. - person Yousf; 23.12.2009
comment
Просто невозможно изменить макрос, а не функцию. Просто невозможно скомпилировать файл, но не выбрать, какой файл компилировать. Вы несете чушь. - person Pete Kirkham; 23.12.2009