2017-02-11 14 views
3

Я пытаюсь преобразовать некоторые Java-код в С. Java код выглядит следующим образом:Получение размера varargs в C?

public static int minimum(int... minimum) { 

    assert(minimum.length > 0); 

    if (minimum.length > 0) 
    .... // some code that i am able to translate to C without any hassle 
} 

Теперь я понимаю, как иметь в С переменным числом аргументов, используя заголовок stdarg.h и использовать макросы, которые. Однако я застрял, выполняя часть minimum.length.

Я пробовал strlen, но терминал дает мне несовместимое целое число для предупреждения об указателе. Есть ли способ в C, где я могу воспроизвести то же самое, что и Java?

ответ

4

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

Косвенным способ сделать это с помощью составных литералов:

#include <stdio.h> 
#include <stdarg.h> 
#include <limits.h> 

#define minimum(...) fnminimum(sizeof((int []) {__VA_ARGS__})/sizeof(int), __VA_ARGS__) 

static int fnminimum(int n, ...) 
{ 
    int num, min = INT_MAX; 
    va_list ap; 

    va_start(ap, n); 
    while (n--) { 
     num = va_arg(ap, int); 
     if (num < min) { 
      min = num; 
     } 
    } 
    va_end(ap); 
    return min; 
} 

int main(void) 
{ 
    int a = 1; 

    printf("%d\n", minimum(2, 30, 7, a++, 4)); 
    return 0; 
} 

Другой (некрасиво) метод с использованием NARGS macros (ограничивается N арг):

#include <stdio.h> 
#include <stdarg.h> 
#include <limits.h> 

#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N 
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1) 

#define minimum(...) fnminimum(NARGS(__VA_ARGS__), __VA_ARGS__) 

static int fnminimum(int n, ...) 
{ 
    int num, min = INT_MAX; 
    va_list ap; 

    va_start(ap, n); 
    while (n--) { 
     num = va_arg(ap, int); 
     if (num < min) { 
      min = num; 
     } 
    } 
    va_end(ap); 
    return min; 
} 

int main(void) 
{ 
    printf("%d\n", minimum(2, 30, 7, 1, 4)); 
    return 0; 
} 

Выход:

1 
+1

Rev 2 '#define minimum .. . очень интересно! Кажется, оценивать аргументы только один раз. Хорошо, если код был 'printf («% d \ n », минимум (a ++, 30, 7, 1, 4));' – chux

+0

Спасибо @chux, отредактирован. И да, 'sizeof' [не оценивает аргументы] (http://stackoverflow.com/a/8225813/1606345) (кроме случаев, когда это массив переменной длины) –

+1

... и _compound literal_ [не может быть VLA] (http://stackoverflow.com/a/14550583/2410359). Хорошее решение. (Я думаю, что это решение должно быть указано до уродливого). – chux

2

Там нет встроенного способа, чтобы получить число vararg аргументов, переданных в С.

Вам нужно выполнить одно из следующих действий:

  • прохода в счете явно
  • (как printf() через число спецификаторов конверсии)
  • или используйте значение контрольной суммы (например, NULL или 0), чтобы указать конец списка vararg

Я видел схемы, которые используют макросы и идентификатор __VA_ARGS__, чтобы автоматически помещать дозор в конце списка varargs при вызове функции.

+0

Если бы я использовал третий вариант, тогда код был бы таким: 'assert (NULL! = Va_arg (vaList, int))' vsList' как наш список аргументов? – Saad

+1

@ Саад: нет. Вы не будете использовать 'assert'. Когда вы выставляете каждое значение из списка ('va_arg (args, type)'), вы должны проверить, является ли значение всплывающим, это значение дозорного - с регулярным выражением 'if'. –

+1

'NULL' - не лучший выбор. C не указывает его _type_, а 'va_arg()' должен знать тип. Значение дозорного должно обязательно иметь тот же тип, что и аргументы. 'Foo_i (1,2, NULL); foo_sa ("1", "2", NULL); foo_sb ("1", "2", 0); "все проблемы. 'foo_sc (" 1 "," 2 ", (char *) 0);' и 'foo_sd (" 1 "," 2 ", (char *) NULL);' are OK – chux