Вызов C ++ (не C) из Common Lisp?

Один урок, на который я склонялся, заключается в том, что вы всегда должны держать его в соответствии! Если вы используете INSERT INTO, не используйте INSERT. Если вы этого не сделаете, некоторые программисты могут снова задать тот же вопрос.

Вот мой другой пример, связанный с примером: у меня была возможность обновить очень длинную хранимую процедуру в MS SQL 2005. проблема в том, что слишком много данных было вставлено в таблицу результатов. Мне нужно было выяснить, откуда пришли данные. Я попытался выяснить, где были добавлены новые записи. В начале раздела SP я увидел несколько INSERT INTO. Затем я попытался найти «INSERT INTO» и обновил их, но я пропустил одно место, где использовался только «INSERT». На самом деле это вставляло 4k + строки пустых данных в некоторые столбцы! Конечно, я должен просто искать INSERT. Однако это случилось со мной. Я обвиняю предыдущего программиста IDIOT:):)

13
задан Jay 7 September 2009 в 03:18
поделиться

4 ответа

Ой, подожди!

Кажется, есть трюк Я могу использовать!

Я пишу оболочку на C ++, объявляя функции оболочки extern "C ":

#include "lib.h"

extern "C" int lib_operate (int i, double *x) {
...
}

Заголовочный файл lib.h, который можно вызывать как из C, так и из C ++, имеет следующий вид:

#if __cplusplus
extern "C" {
#endif

int lib_operate (int i, double *x);

#if __cplusplus
}
#endif

Затем скомпилируйте с помощью:

g++ -c lib.cpp
gcc -c prog.c
gcc lib.o prog.o -lstdc++ -o prog

Похоже, это работает для игрушечного примера! : -)

Итак, в Common Lisp я бы вызвал оболочку после загрузки libstdc ++.

В любом случае, спасибо за ваши ответы!

7
ответ дан 1 December 2019 в 18:49
поделиться

После компиляции большинство функций C ++ фактически сводятся к минимуму. к обычным вызовам функций C. Из-за перегрузки функций и других возможностей компиляторы C ++ используют изменение имен , чтобы различать функции с одинаковыми именами. Имея утилиту для создания дампа объекта и имея достаточные знания о вашем компиляторе C ++, вы можете вызывать код C ++ непосредственно из внешнего мира.

Однако, сказав это, вам может быть проще написать C-совместимый слой между Lisp и вашим кодом C ++ . Это можно сделать с помощью extern "C" , например:

extern "C" Foo *new_Foo(int x)
{
    return new Foo(x);
}

Это заставляет функцию new_Foo () следовать соглашению о вызовах C, так что вы можете вызывать ее из внешних источников.

17
ответ дан 1 December 2019 в 18:49
поделиться

Основное различие в вызове функций C ++ вместо функций C, помимо изменения имени, - это «скрытые» функции, такие как указатели this , которые неявно передаются функциям-членам. Слой времени выполнения C ничего не знает об этих, неявных преобразованиях типов и других интересных функциях C ++, поэтому, если вы собираетесь вызывать C ++ через интерфейс C, вам, возможно, придется при необходимости подделать эти функции.

Предполагая, что вы можете удерживая по крайней мере void * для объекта, который вы собираетесь вызвать, и требуемых данных, вы можете преобразовать следующий вызов C ++

matrix->multiply(avector);

в вызов C, если вы создадите функцию-оболочку C:

extern "C"
void matrix_multiply(void *cpp_matrix, void *cpp_vector) {
  reinterpret_cast<matrix_type *>(cpp_matrix)->multiply(reinterpret_cast<vector_type *>(cpp_vector);
}

Очевидно, что функция matrix_multiply будет сидеть в исходном коде C ++ и скомпилирован как таковой, но открывает интерфейс C для внешнего мира. Пока вы можете взаимодействовать с непрозрачными указателями, вы в порядке с прокладками перевода, указанными выше.

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

Другой вариант - выполнять вызовы C ++ напрямую, обрабатывая их как вызовы C с дополнительными параметрами и самостоятельно предоставляя всю необходимую информацию, но это действительно очень быстро перемещает вас в область кода, специфичного для компилятора. По сути, вы по-прежнему будете удерживать непрозрачные указатели на объекты C ++, но вам придется определить искаженное имя функции, которую вы хотите вызвать. После того, как вы получили это имя функции, вам нужно будет предоставить указатель this (который неявный в C ++ и полунявный в приведенном выше примере) и правильные параметры, а затем вызвать функцию.

13
ответ дан 1 December 2019 в 18:49
поделиться

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

Или, если у вас есть гарантия без броска для завернутого кода, вы можете игнорировать все это.

3
ответ дан 1 December 2019 в 18:49
поделиться