Использование директив препроцессора для определения общих функций в C

Я только что перешел на C с C # и искал способ определения общих функций, подобных тем, что есть в C #. Я наткнулся на этот пост но когда я попытался скомпилировать его, я получил кучу ошибок («` n 'здесь необъявлено (не в функции) »,« синтаксическая ошибка перед «массивом» »и т. д.) Вот мой код:

#include<conio.h>
#include<stdlib.h>

#define MAKE_PRINTEACH(TYPE)\
void printeach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)){\
  int i;\
  for(i = 0; i < n; i++) {\
    f(array[i]);\
  }\
}

MAKE_PRINTEACH(int)
MAKE_PRINTEACH(float)

void printInt(int x)
{
     printf("got %d\n",x);
}

void printFloat(float x)
{
     printf("got %f\n",x);
}

int main()
{
    int[5] ia = {34,61,3,6,76};
    float[6] fa = {2.4,0.5,55.2,22.0,6.76,3.14159265};

    printeach_int(ia, 5, printInt);
    printeach_float(fa,6,printFloat);

    getch();
}

Что я здесь делаю не так? Я использую DevC ++, если это имеет значение.


person Zak Gambrell    schedule 12.10.2012    source источник
comment
Хм, я подумал, что тег function будет более подходящим, чем тег functional programming, но теперь я не уверен. Если вы не согласны, можете откатиться назад.   -  person Matt Fenwick    schedule 12.10.2012
comment
Что означает n в скобках во второй строке определения макроса? Может, стоит его пропустить?   -  person supercat    schedule 12.10.2012
comment
При отладке макроса, подобного этому, часто бывает полезно просто передать вашу программу препроцессору C и посмотреть, что появится. gcc -E program.c   -  person Clinton Pierce    schedule 12.10.2012


Ответы (2)


Правильная версия будет выглядеть так

#define MAKE_PRINTEACH(TYPE)                                     \
void printeach_##TYPE (size_t n, TYPE array[n], void(*f)(TYPE)){ \
  for(size_t i = 0; i < n; i++) {                                \
    f(array[i]);                                                 \
  }                                                              \
}

подытожим, что пошло не так с вашей версией:

  • n должен быть объявлен перед использованием
  • границы массива идут после идентификатора
  • семантически правильный тип для размеров массивов и тому подобного - size_t
  • C, начиная с C99, также имеет локальные переменные для for циклов.
person Jens Gustedt    schedule 12.10.2012
comment
О, хорошо, теперь я понимаю. Спасибо за информацию о size_t - person Zak Gambrell; 13.10.2012

Вы можете попробовать этот вариант:

#define MAKE_PRINTEACH(TYPE)\
void printeach_##TYPE (TYPE * array, int n, void(*f)(TYPE)){\
  int i;\
  for(i = 0; i < n; i++) {\
    f(array[i]);\
  }\
}

TYPE[n] array подразумевает, что компилятор поддерживает VLA (массив переменной длины), и я не знаю, поддерживает ли ваш компилятор.

gcc добавление параметра командной строки -std=c99 приведет к компиляции исходного кода.

Обновление: исправления, внесенные в соответствии с комментарием Йенса.

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

Также Йенс упоминает несколько других предупреждений / ошибок. Как есть:

1 conio.h не является стандартным включением C, stdio.h здесь может быть уместно

2 Массивы объявляются путем добавления размера массива к имени переменной, а не к типу. Должно быть: int ia[5]не int[5] ia

3 main() возвращает int, OP ничего не возвращает.

4 Отсутствует прототип для getch(). Можно включить curses.h

person alk    schedule 12.10.2012
comment
-1, исходный код не содержит нескольких ошибок и не будет компилироваться с -std=c99. Вы действительно должны научить Зака, что пошло не так в его версии, а не только как избежать проблемы. - person Jens Gustedt; 13.10.2012
comment
Спасибо за исправление. Я должен был прислушаться к внутреннему голосу, который шепчет, что то, что я пишу о VLA, было чепухой. @JensGustedt - person alk; 13.10.2012