2015-03-14 2 views
1

Я пытаюсь написать макрос, который возвращает наименьшее значение нескольких целых чисел. Когда я компилирую следующий код, он генерирует ошибку «ожидаемое выражение». Я не знаю, что там не так. Может ли кто-нибудь указать на проблемы с этим кодом?C Макро с varargs

#define SMALLEST (nums, (ret_val), ...)   \ 
do {            \ 
    int i, val;         \ 
    va_list vl;         \ 
    va_start(vl,nums);       \ 
    (*ret_val) = va_arg(vl, int);    \ 
    for (i = 1; i < nums; i++)     \ 
    {           \ 
     val=va_arg(vl, int);      \ 
     if ((*ret_val) > val)     \ 
      (*ret_val) = val;     \ 
    }           \ 
    va_end(vl);         \ 
} while(0) 

int main() 
{ 
    int nums = 3; 
    int ret_val = 0; 
    SMALLEST(nums, &ret_val, 1, 2, 3); 
    return 0; 
} 

Мне просто интересно, как это сделать с помощью макроса.

+0

Ваш синтаксис для макросов неверен. Между именем макроса и '()' не должно быть пробела. Параметры макроса в списке параметров не могут быть помещены в дополнительные '()'. –

ответ

4

Мне просто интересно, как это сделать с помощью макроса.

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

Однако, если вы действительно настаиваете на использовании VARIADIC макрос, то получается, что вам повезло, что тот же сепаратор , используется в макро-аргументов и в инициализаторах массива, так что вы можете попробовать что-то вроде:

#define F(X, ...) \ 
    do { \ 
    int t[] = { __VA_ARGS__ }; \ 
    for (int i = 0; i < sizeof t/sizeof t[0]; i++) \ 
     … \ 
    } while (0) 
2

Я не думаю, что вы можете. Из руководства gcc (https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html) лучшее, что вы можете сделать стандартным способом, это написать __VA_ARGS__, который расширит аргументы на месте (например, перейти к функции).

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

Почему бы не сделать это с функцией?

0

Это не имеет смысла делать это с помощью макроса. Вот для чего нужны функции.

Вы получаете сообщение об ошибке, поскольку символ SMALLEST в вашей основной функции заменяется всем телом функции, которую вы определили. AFAIK вы не можете определить функцию внутри другой функции в C.

0

То, как вы обрабатываете списки аргументов в переменных массивах, не совпадает с тем, как вы справляетесь с ними в вариационных функциях. Вместо использования va_list и связанных с ним макросов вы используете __VA_ARGS__.

Это почти такая степень: вы не можете написать макрос, который обрабатывает вариационный список от начала до конца; вы ограничены передачей аргументов через переменную функцию, которая выполняет фактическую обработку.

Примечание: Ваша реализация неправильна, тоже: вы должны использовать va_start(vl,ret_val) вместо va_start(vl,nums), потому что вы должны пройти последний аргумент, прежде чем ... к va_start.

Если бы я должен был переписать это как функцию, я бы сбросил указатель ret_val и сделаю функцию, которая возвращает значение обычным способом.

0

Есть ли какая-то особая причина, по которой вы хотите использовать макрос здесь? Кажется, вы смешиваете макроса синтаксис и стандартный синтаксис (причина вашей ошибки).

Для достижения этой цели вы должны использовать функцию - для чего предназначена функция. Следующий код должен получить, что вы хотите:

int Smallest(int iNumberOfIntegers, ...) 
{ 
    va_list args = NULL; 
    int i = 0; 
    int iSmallestValue = 0; 
    int iCurrentValue = 0; 

    va_start(args, iNumberOfIntegers); 
    iSmallestValue = va_arg(args, int); 

    for(i = 0; i < iNumberOfIntegers - 1; i++) 
    { 
     iCurrentValue = va_arg(args, int); 
     if(iSmallestValue > iCurrentValue) 
     { 
      iSmallestValue = iCurrentValue; 
     } 
    } 

    return iSmallestValue; 
} 
  • Следует отметить, что вам нужно передать размер VARIADIC аргумента, если вы собираетесь петлю над ним таким образом. Это необязательно в строках формата, поскольку компилятор может вывести число из спецификаторов строки форматирования.
  • Мы вычитаем 1 из цикла для учета смещения 0.

Редактировать: И, как говорили другие, вы не можете использовать переменный макрос в том виде, в котором вы пытались.

Смежные вопросы