LINUX.ORG.RU

Optional variables in C.


0

0

[Д|б]одрого времени суток, столкнулся со следующая проблемой:
имеется функция:

phis_init( int *flags)

Необходимо добавить новый параметер:

phis_init (int *flags, char *path)
^^^^^^^^^^
при этом параметер path может либо присутсвовать либо отсутствовать в вызове функции. Возможно ли это сделать ? Если да, то как ?

Заранее благодарен,
Vic.


Конечно можно. Функции с пременным числом аргументов описаны в книге Кернигана и Ритчи. Можно посмотреть на stdarg.h (там макросы опредлены).

parser ★★
()
Ответ на: комментарий от parser

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

Я думаю чтобы максимально имитировать С++ нужно использовать variadic macros

dilmah ★★★★★
()
Ответ на: комментарий от psi

> Да, Вы правы. Функция сама должна узнавать сколько параметров ей передали.

Это чисто академический интерес? Потому что, по-моему, в реальной ситуации всегда можно обойтись, например, так:

void foo(int a, char *c)
{
    if(c){
        // code
    }
}

foo(10, NULL);

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

shumer
()
Ответ на: комментарий от shumer

К сожалению интерес практический. Дело в том, что это вызов этой функции есть во многих программах. Хочется совместимости. То есть вызов:

call phis_init(INIT)

валиден,
но возможен

call phis_init(INIT,PATH)

что дает некоторые новые возможности.

Более того, я в замешательстве, ибо в F90 это делается очень легко.

Best wishes,
Vic.

psi
() автор топика
Ответ на: комментарий от psi

А использовать C (а не С++) обязательно? На С++ это делается очень легко:

int foo(int a, int b = 0)
{
  ...
}

Begemoth ★★★★★
()

в таких случаях надо передавать класс/структуру в качестве параметра,
а в ней не забыть предусмотреть поле версии структуры, чтобы когда
поменяешь кол-во параметров, функция могла это разрулить. Новые
структуры параметров _только_ наследовать от предыдущих, чтобы каждая
из них всегда могла поддерживаться. Типа такого:

#include <stdio.h>

struct SParamBase {
 int iVersion;
};

struct SParamSet1: public SParamBase {
 int *flags;
};

struct SParamSet2: SParamSet1 {
 char *path;
};

void phis_init(SParamBase *par){
 // все версии должны поддерживаться!
 switch(par->iVersion){
  case 0:{
    printf("1 para\n");
      SParamSet1 *set1 = 0;
      // надо ещё размер структуры проверять - опустим
      set1 = (SParamSet1*)par;
      printf("flags[0]=%d\n", set1->flags[0]);
    }
    break;
  case 1: {
      SParamSet2 *set2 = 0;
      printf("2 para\n");
      set2 = (SParamSet2*)par;
      printf("flags[0]=%d, par2=%s\n", set2->flags[0], set2->path);
    }
    break;
  default:
    printf("error: version not supported\n");
    break;
 }
}

int main(){
 int flags1[] = {1,2,3};
 int flags2[] = {6,5,4};
 char path[] = "C:\\path";

 SParamSet1 par1;
 par1.iVersion = 0;
 par1.flags = flags1;
// один параметр
 phis_init(&par1);

 SParamSet2 par2;
 par2.iVersion = 1;
 par2.flags = flags2;
 par2.path = path;
// ...а теперь два
 phis_init(&par2);
}

BookWarrior
()
Ответ на: комментарий от psi

у вас вызов из Фортрана? Об этом надо обязательно сообщать в постановке задачи. Фортран совсем иначе работает с параметрами, он их передаёт по ссылке. Да и структур в нём нет. Вы попали :)

Можно ломиться сквозь дебри неудобного для программирования языка программирования: http://www.skgtu.ru/romanebook/lections/ootp/GLAVA~49.HTM (тут о структурах в фортране)

А можно попытаться создать адаптер для всех возможных вариантов вашей функции.

Вместо phis_init() вам нужно написать другую функцию (адаптер), скажем phis_init_a1(), которая будет принимать 1 параметр, phis_init_a2() - два параметра. Тогда внутри вызываться будут конкретные phis_init, с одним или двумя параметрами только. Это как вариант. Можно подумать о других решениях подобного рода (не уверен, что вам предложенное подходит). Идея в том, чтобы сделать вызов C++ функции с фиксированным кол-вом параметров, а диспетчирезацию (адаптацию) осуществить на фортране, как бы разгрузить сложность передачи параметров. Это сработает, если вы знаете все случаи вызовов вашей функции: с какими параметрами она вызывается и сколько их, - и напишете свой адаптер для каждого вызова.

BookWarrior
()

Можно не декларировать функцию, отключить ворнинги в gcc, но действовать на свой страх и риск.

Chumka ★★★
()
Ответ на: комментарий от BookWarrior

А не проще перейти на С++? В таких случаях используются либо параметры по умолчанию, либо перегрузка функци.

Begemoth ★★★★★
()
Ответ на: комментарий от BookWarrior

Спасибо за Ваши ответы и примеры.
В фортране уже много чего есть, в фортране 90-ом-). Но это не важно в данном случае. Есть люди, которые пишут на 77-ом. Мы решили через переменные окружения тянуть эти пути.

С наилучшими полжеланиями,
Vic.

P.s. С C++ попробую, как время будет. Интересное решение

psi
() автор топика

Шарик, 
Поздравляю с новым годом, 
ты балбес!

Как такой вариант?: 

sometype phis_init_ИНАЯ( int *flags, char *path)
{
    .. все реализовано тут ...
} 

sometype phis_init (int *flags) 
{
    return phis_init_ИНАЯ(flags, NULL);
}

anonymous
()
Ответ на: комментарий от anonymous

А ты сам пробовал то что написал ? Я смотрю тебя снова на поток сознания/полет мысли вынесло.

psi
() автор топика
Ответ на: комментарий от psi

> А ты сам пробовал то что написал ? Я смотрю тебя снова на поток сознания/полет мысли вынесло.

Кого это "тебя" ?

По сути - да пробовал, и постоянно используют этот прием, когда нужно на чистом С сохранить и совместимость со старым способом вызова, и добавить новый аргумент. Все прекрасно работает. Где я не прав?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.