kzen.dev
  • Вопросы
  • Метки
  • Пользователи
Оповещения
Вознаграждения
Регистрация
После регистрации, сможете получать уведомления об ответах и комментариях на Ваши вопросы.
Вход
Если у Вас уже есть аккаунт, войдите чтобы проверить новые уведомления.
Тут будут вознаграждения за добавленные вопросы, ответы и комментарий.
Дополнительно
Источник
Редактировать
 andrewrk
andrewrk
Вопрос

Передача дополнительных параметров в указателях функций языка Си

Допустим, я создаю шахматную программу. У меня есть функция

void foreachMove( void (*action)(chess_move*), chess_game* game); 

которая будет вызывать функцию-указатель action на каждом правильном ходу. Это все хорошо, но что если мне нужно передать больше параметров в функцию action? Например:

chess_move getNextMove(chess_game* game, int depth){
  //for each valid move, determine how good the move is
  foreachMove(moveHandler, game);
}

void moveHandler(chess_move* move){
  //uh oh, now I need the variables "game" and "depth" from the above function
}

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

Как я могу передать дополнительные параметры в функцию, которую я вызываю через указатель?

9 2008-08-14T16:51:07+00:00 9
 Community
Community
Редактировал вопрос 9-го сентября 2008 в 9:13
Программирование
c
architecture
pointers
Анонимный пользователь
14-го августа 2008 в 5:19
2008-08-14T17:19:28+00:00
Дополнительно
Источник
Редактировать
#8415157

Ах, если бы только C поддерживал закрытия...

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

  1. Пусть последним аргументом в вашем прототипе будет void*. Это даст вам возможность передавать все остальное, что вам нужно, но это определенно небезопасно для типов.
  2. Используйте переменные параметры (...). Учитывая отсутствие опыта работы с переменными параметрами в C, я не уверен, можно ли использовать это с указателем функции, но это дает еще большую гибкость, чем первое решение, хотя и с отсутствием безопасности типов.
  3. Перейти на C++ и использовать функциональные объекты.
11
0
Antonio Haley
Antonio Haley
14-го августа 2008 в 4:58
2008-08-14T16:58:47+00:00
Дополнительно
Источник
Редактировать
#8415156

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

void foreachMove( void (*action)(chess_move*, int), chess_game* game )
8
0
Jesse Beder
Jesse Beder
14-го августа 2008 в 5:32
2008-08-14T17:32:18+00:00
Дополнительно
Источник
Редактировать
#8415159

Если you' ре, готовое использовать некоторый C ++, Вы можете использовать " функция object":

struct MoveHandler {
    chess_game *game;
    int depth;

    MoveHandler(chess_game *g, int d): game(g), depth(d) {}

    void operator () (chess_move*) {
         // now you can use the game and the depth
    }
};

и поверните свой < code> foreachMove в шаблон:

template <typename T>
void foreachMove(T action, chess_game* game);

и Вы можете назвать его как это:

chess_move getNextMove(chess_game* game, int depth){
    //for each valid move, determine how good the move is
    foreachMove(MoveHandler(game, depth), game);
}

но это won' t разрушают Ваше другое использование < code> MoveHandler.

5
0
 Baltimark
Baltimark
14-го августа 2008 в 5:24
2008-08-14T17:24:57+00:00
Дополнительно
Источник
Редактировать
#8415158

Если я правильно понял, то я бы предложил сделать так, чтобы ваша функция принимала в качестве аргумента указатель на struct. Тогда ваша структура может иметь "игру" и "глубину", когда они ей нужны, и просто оставить их установленными в 0 или Null, когда они вам не нужны.

Что происходит в этой функции? Есть ли у вас условие, которое говорит,

if (depth > -1) //some default
  {
  //do something
  }

Всегда ли функция требует "игру" и "глубину"? Тогда они всегда должны быть аргументами, и это можно включить в прототипы.

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

Но иметь структуру в качестве аргумента, вероятно, проще всего.

Adam Tyszecki
Adam Tyszecki
Редактировал ответ 24-го ноября 2016 в 10:22
3
0
Nathan Fellman
Nathan Fellman
14-го августа 2008 в 6:15
2008-08-14T18:15:26+00:00
Дополнительно
Источник
Редактировать
#8415160

I' d предлагают использовать множество пустоты* с последним входом всегда пустота. скажите, что Вам нужны 3 параметра, Вы могли сделать это:

void MoveHandler (void** DataArray)
{
    // data1 is always chess_move
    chess_move data1 = DataArray[0]? (*(chess_move*)DataArray[0]) : NULL; 
    // data2 is always float
    float data1 = DataArray[1]? (*(float*)DataArray[1]) : NULL; 
    // data3 is always char
    char data1 = DataArray[2]? (*(char*)DataArray[2]) : NULL; 
    //etc
}

void foreachMove( void (*action)(void**), chess_game* game);

и затем

chess_move getNextMove(chess_game* game, int depth){
    //for each valid move, determine how good the move is
    void* data[4];
    data[0] = &chess_move;
    float f1;
    char c1;
    data[1] = &f1;
    data[2] = &c1;
    data[3] = NULL;
    foreachMove(moveHandler, game);
}

Если все параметры - тот же тип тогда, Вы можете избежать, чтобы пустота* выстроила и просто послала ЗАКОНЧЕННОЕ ПУСТЫМ УКАЗАТЕЛЕМ множество любого типа, в котором Вы нуждаетесь.

1
0
Derek Park
Derek Park
14-го августа 2008 в 6:39
2008-08-14T18:39:46+00:00
Дополнительно
Источник
Редактировать
#8415161

+1 Антонио. Вы должны изменить свою декларацию указателя функции, чтобы принять дополнительные параметры.

Кроме того, пожалуйста, don' t начинают раздавать недействительные указатели или (особенно) множества недействительных указателей. That' s просто напрашивающийся на неприятности. Если Вы начинаете мимолетные недействительные указатели, you' ре, собирающееся также должным быть передать некоторое сообщение, чтобы указать на то, что тип указателя (или типы). Эта техника редко соответствующая.

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

0
0
Dale Ragan
Dale Ragan
14-го августа 2008 в 8:22
2008-08-14T20:22:54+00:00
Дополнительно
Источник
Редактировать
#8415162

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

http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html

Просто к вашему сведению, о примере кода в связи: некоторые места, которые они имеют “n args” и другие, это - «n_args» с подчеркиванием. У них должно все быть подчеркивание. Я думал, что синтаксис выглядел немного забавным, пока я не понял, что они пропустили подчеркивание в некоторых местах.

0
0
 roo
roo
16-го сентября 2008 в 2:57
2008-09-16T14:57:42+00:00
Дополнительно
Источник
Редактировать
#8415163

Используйте typedef для указателя функции. Посмотрите мой ответ для этот вопрос

 Community
Community
Редактировал ответ 23-го мая 2017 в 11:53
0
0
luser droog
luser droog
8-го апреля 2013 в 5:08
2013-04-08T05:08:22+00:00
Дополнительно
Источник
Редактировать
#8415164

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

0
0
Добавить вопрос
Категории
Все
Технологий
Культура / Отдых
Жизнь / Искусство
Наука
Профессии
Бизнес
Пользователи
Все
Новые
Популярные
1
Ilya Smirnov
Зарегистрирован 5 дней назад
2
Денис Васьков
Зарегистрирован 1 неделю назад
3
Dima Patrushev
Зарегистрирован 1 неделю назад
4
sirojidddin otaboyev
Зарегистрирован 2 недели назад
5
Елена Гайдамамакинат
Зарегистрирован 2 недели назад
ID
KO
RU
© kzen.dev 2023
Источник
stackoverflow.com
под лицензией cc by-sa 3.0 с атрибуцией