Взаимодействие вариативной функции C и Fortran

Есть ли способ объявить вариативную функцию C и вызвать ее из Fortran? Мне нужно вызвать эту функцию, чтобы вычислить некоторые скалярные произведения между векторами, помеченными строкой. Моя идея состояла в том, чтобы объявить что-то вроде следующего, где переменный список аргументов содержит строковые литералы. Если переменный список аргументов пуст, я бы сделал поиск среди стандартных меток и выполнил вычисление. Если бы пользователь указал две метки, я бы извлек эти два вектора и получил их точечный продукт:

extern "C" void compute_dot_product(double * dot_product, ...)
{
    va_list args;
    va_start(args, NULL);
    char * label1 = va_arg(args, char *);
    if (!label1)
    {
       // Do standard label lookup and compute dot product
    }
    else
    {
       // Compute dot product between the vectors with the specified labels
       char * label2 = va_arg(args, char *);
    }
    va_end(args);
}

единственная проблема заключается в том, что я могу скомпилировать свою библиотеку C и связать ее с исполняемым файлом Fortran, но я получаю ошибку времени выполнения, когда пытаюсь получить доступ к списку переменных аргументов. Есть идеи, возможно ли то, что я пытаюсь сделать? Тогда возможным решением было бы разделение на две функции: одна выполняет стандартный поиск метки (с 0 аргументами), другая обрабатывает нестандартный поиск метки (с 2 аргументами). Я бы предпочел избежать этого решения, хотя.


person boberto    schedule 30.10.2013    source источник
comment
Он должен быть объявлен как cdecl с обеих сторон. Ваша ошибка времени выполнения может быть связана с тем, что одна сторона — stdcall, а другая — cdecl.   -  person cup    schedule 18.12.2013


Ответы (1)


Невозможно вызвать вариационную функцию стандартным (то есть переносимым) способом.

Вы можете сделать так, чтобы определение функции C принимало только два параметра (чтобы оно больше не было вариативным - существующие ссылки на функцию должны быть изменены), со вторым параметром в функции C указателем, либо NULL, чтобы указать, что существует никакие дополнительные вещи не передаются или не указывают на массив указателей (возможно, с завершением NULL) или что-то еще, с какими-либо дополнительными вещами. В F201X тело интерфейса для такого рода функций может использовать НЕОБЯЗАТЕЛЬНЫЙ атрибут для второго аргумента.

person IanH    schedule 30.10.2013
comment
Это то, что делает вариационная функция. См.: stackoverflow.com/a/19171063/1162141. - person technosaurus; 30.10.2013
comment
@technosaurus Я не вижу актуальности комментария или связанного ответа. - person IanH; 30.10.2013
comment
Функция ... в вариативной функции, по сути, представляет собой массив указателей (хотя они могут быть целочисленными типами). Ссылка показывает несколько сложный способ выполнения этих приведений для получения правильного типа, начиная с первого указателя. Так что ваш ответ имеет смысл заменить ... +1. - person technosaurus; 30.10.2013
comment
Я не понимаю, почему этот интерфейс работает тогда целочисленная функция printf(format, item1, item2) bind(C) import character(kind=c_char) :: format(*) integer(c_int), value :: item1, item2 end function - person Vladimir F; 30.10.2013
comment
Ты спрашиваешь меня? Если да, то «работает» /= «соответствует стандарту», ​​но вы это знаете. - person IanH; 30.10.2013
comment
Я определенно не эксперт ни в C, ни в вариативных функциях. Я действительно предполагал, что это правильный путь раньше. - person Vladimir F; 30.10.2013
comment
Я имею в виду, что я всегда предполагал, что переменные аргументы передаются так же, как и все остальные (по значению), и подпрограмма просто использует строку формата, чтобы увидеть, сколько из них помещено в стек (или в регистры) и как их интерпретировать. - person Vladimir F; 30.10.2013
comment
Хорошо, теперь я понял. Вы (или технозавр) описывали не то, как работают вариативные функции, а то, как сделать их альтернативой. - person Vladimir F; 30.10.2013
comment
В моем случае - да - это было моим намерением - я перефразирую, чтобы было понятно. Ваше предполагаемое понимание того, как могут быть реализованы (и почти всегда реализуются) вариативные функции, такое же, как у меня — макросы для доступа к ним просто возвращаются вверх по стеку. Я не думаю, что они обычно реализуются путем передачи массива указателей. Я думаю, вам понадобится довольно экзотический компилятор C, чтобы это работало. Но я не компилятор C или Fortran - я просто слепо следую правилам языка. - person IanH; 31.10.2013