Консультация № 181266
12.12.2010, 23:47
65.56 руб.
0 27 1
Здравствуйте, уважаемые эксперты!

У меня стоит задача: некоторые функции написанные на Си надо включить в программу на Паскале. Для программы используется Borland Pascal 7 (Delphi пока нельзя). Для функций -- Borland C++ 3.1 (можно другой, но что есть для DOS?)

Проблема 1. Компилятор Паскаля успешно линкует obj файл, но не находит функции. При включении в Си опции "Generate assembler code" обнаружил, что функциям даются чудные имена. Например, функция int qwe(int i) там называется @qwe$qi. Я поменял вручную имена на qwe, скопилировал obj в tasm и в Паскале всё правильно заработало. Откуда такое название? Как это отключить?

Проблема 2. Эти функции на Си -- математические; там используются abs, sin и прочее из math.h. Когда я их добавил, Паскаль сказал, что не находит _abs, _sin. Как можно справиться с этим затруднением?

Обсуждение

Неизвестный
13.12.2010, 06:52
общий
15.12.2010, 19:41
это ответ
Здравствуйте, Сергей Бендер!

Средствами Borland C++ 3.1 создайте DLL со всеми необходимыми функциями, а затем подключите этот DLL в Borland Pascal.

Решение проблемы №1: Для того, чтобы имена собственных функций экспортировались в объектный файл в том виде, в каком они присутствуют в исходном коде программы, необходимо добавлять в определении функции ключевое слово pascal, например:
Код:
double pascal qwe(double d)

Решение проблемы №2: Для передачи в программу на Паскале функционала математических функций, таких как sin, cos, log, exp и т.д. при невысоких требованиях к производительности, данные функции проще всего реализовать в исходной программе на C путем вычисления суммы N членов ряда Тейлора, в который можно разложить указанные функции. На практике достаточно 3-4 членов ряда.
Разложение в ряд с примерами описано здесь: http://ru.wikipedia.org/wiki/Ряд_Тейлора
5
В первую очередь за то, что долго обсуждали и перебирали варианты.
Неизвестный
13.12.2010, 09:56
общий
функция int qwe(int i) там называется @qwe$qi

Это называется name mangling
Объявляйте функции как-то так:
Код:

int pascal qwe(int i)

и не используйте c++
давно
Профессионал
304622
583
13.12.2010, 14:32
общий
Цитата: 303901
и не используйте c++


Поменять расширение с .cpp на .c?
давно
Профессионал
304622
583
13.12.2010, 15:00
общий
Насколько я понял Вы предлагаете способ обеспечить использование внешних функций sin, abs и т.д. А через простой obj это в принципе невозможно?

Средствами Borland C++ 3.1 создайте DLL со всеми необходимыми функциями


Как это делается? Я такого раньше не делал. Знаю только в меню Options->Application пунктик Windows DLL. Это оно? В тексте надо что-то прописывать?

Предположим, вот тестовый пример, файл asd.c:
Код:

#include <math.h>

double pascal qwe(double d)
{
return sin(d)+100;
}


а затем подключите этот DLL в Borland Pascal.

Мне помнится, что этого нельзя сделать в Real mode, надо переключаться в Protected mode. Это так?

И как это делается? Мне помнится там что-то многосложное надо прописывать.

Например, тестовый файл zxc.pas:
Код:

function qwe(i:double):double;external;
{$L asd.obj}

begin
writeln(qwe(3):0:3);
readln;
end.


С учётом того, что предложил vladisslav, в asd.c всё скопилировалось и заработало, но(!) без использования sin. А он критически важен. Как присоединять DLL?
Неизвестный
13.12.2010, 20:52
общий
Адресаты:
Для начала попробуйте вот такой вариант:

Код:
#include <math.h>
double pascal qwe(double d)
{
return sin(d)+100;
}

Здесь ключевое слово pascal сгенерирует имя функции qwe в таком виде, как оно есть.

И укажите компилятору bcc дополнительную опцию: -u-
При этом функция sin будет также без подчеркивания.
давно
Профессионал
304622
583
13.12.2010, 21:53
общий
Не понял. Вы по прежнему имеете в виду создание DLL или предлагаете попробовать досовский obj?

Скомпилировал obj с опцией -u-. В Паскале сказали:
==
Error 52: Invalid EXTRN definition (sin).
==
В F1 поясняют
==
■ The identifier was referred to through an
EXTRN directive in assembly language, but it
is not declared in the Pascal program or unit,
nor in the interface part of any of the used
units.
==

Насколько я понимаю функция sin в obj всё равно не включится? Неужели Паскаль сможет привязать вызов к собственному sin?

Я думал, что Вы предлагаете компилировать DLL, потому что туда вызываемые функции (sin, abs и т.д.) будут включаться. Так?
Неизвестный
14.12.2010, 06:48
общий
Адресаты:
Паскаль не находит sin, т.к. Вы не подключили библиотеку с данной функцией при компоновке программы.

Для того, чтобы реализовать вариант через DLL, необходимо в определении функций на C++ добавить: __declspec(dllexport)
А в Паскале описать все указанные функции с использование ключевого слова external;
давно
Профессионал
304622
583
14.12.2010, 12:30
общий
Паскаль не находит sin, т.к. Вы не подключили библиотеку с данной функцией при компоновке программы


Я должен был подключить эту библиотеку в Паскале? Или в С?
Неизвестный
14.12.2010, 12:33
общий
Адресаты:
В Паскале конечно.
Как Вы думаете откуда линковщик возьмет эту функцию? В исходном коде на ассемблере ее нет, ссылки на стандартную dll тоже нет.
Подключайте соответствующую библиотеку Паскаля с функцией синуса.
давно
Профессионал
304622
583
14.12.2010, 12:46
общий
Для того, чтобы реализовать вариант через DLL, необходимо в определении функций на C++ добавить: __declspec(dllexport)


Сделал так:
Код:

#include <math.h>

double __declspec(dllexport) qwe(double d)
{
return sin(d)+100;
}


В меню в меню Options->Application выбрал Windows DLL.
BCсказал:
Error ASD.C 3: Declaration was expected
Warning ASD.C 6: Parameter 'dllexport' is never used

Вы уверены, что Borland C++ знает про __declspec(dllexport)?
давно
Профессионал
304622
583
14.12.2010, 13:04
общий
Подключайте соответствующую библиотеку Паскаля с функцией синуса.


А-а-а! Вот что Вы имеете в виду! В Паскале функция sin уже поlключена. (Конкретно: она находится в библиотеке system, которая подключается по умолчанию всегда.)

Пока я не использовал BC опцию -u-, Паскаль действительно не находил функцию _sin ("Undefined external (_sin)"). Но сейчас-то опция -u- уже включена, и Паскаль говорит: Invalid EXTRN definition (sin). Знает Паскаль про sin, но, насколько я понимаю, не принимает тот вызов, который обнаруживает в obj-файле. Хм-м.
Неизвестный
14.12.2010, 13:21
общий
Адресаты:
По поводу создания DLL покажите полную команду, как запускаете компиляцию?
давно
Профессионал
304622
583
14.12.2010, 13:50
общий
Я нажимаю F9 в оболочке IDE. В том BC3.1, что у меня сейчас под рукой, файла bcc.exe почему-то нет.

Могу показать настройки оболочки:
Код:

В Options->Application
Current Settings

Linker output Windows DLL
Prolog/Epilog Windows DLL all functions exportable
Model Compact
Assume SS equals DS Never
-----------------------
В Options->Compiler->Code Generation
Model Options
( ) Tiny [X] Treat enums as ints
( ) Small [ ] Word alignment
( ) Medium [ ] Duplicate strings merged
(•) Compact [ ] Unsigned characters
( ) Large [ ] Pre-compiled headers
( ) Huge [ ] Generate assembler source
[ ] Compile via assembler

Assume SS Equals DS
( ) Default for memory model
(•) Never
( ) Always
-------------------------
В Options->Compiler->Advanced Code Generation
Floating Point Options
( ) None [ ] Generate underbars
( ) Emulation [ ] Line numbers debug info
( ) 8087 [X] Debug info in OBJs
(•) 80287/387 [ ] Browser info in OBJs
[X] Fast floating point
Instruction Set [ ] Fast huge pointers
( ) 8088/8086 [ ] Generate COMDEFs
( ) 80186 [ ] Automatic far data
( ) 80286
(•) 80386 Far Data Threshold 32767
----------------------
В Options->Compiler->Entry/Exit Code Generation
Prolog/Epilog Code Generation
( ) DOS standard
( ) DOS overlay
( ) Windows all functions exportable
( ) Windows explicit functions exported
( ) Windows smart callbacks
(•) Windows DLL all functions exportable
( ) Windows DLL explicit functions exported

Calling Convention Stack Options
( ) C [X] Standard stack frame
(•) Pascal [ ] Test stack overflow
( ) Register
--------------------
Ещё в Options->Compiler есть пунктики
C++ options...
Advanced C++ options...
Optimizations...
Source...
Messages
Names...
----------------
В Options->Make
Break Make On
( ) Warnings
(•) Errors
( ) Fatal errors
( ) All sources processed

After Compiling
( ) Stop
(•) Run linker
( ) Run librarian

Generate Import Library
( ) No
(•) Use DLL file exports
( ) Use DEF file exports

[X] Check auto-dependencies
-------------
В Options->Linker->Settings
Map File Options
(•) Off [ ] Initialize segments
( ) Segments [X] Default libraries
( ) Publics [ ] Pack code segments
( ) Detailed [ ] Warn duplicate symbols
[X] "No stack" warning
[X] Case-sensitive link
Output [ ] Case-sensitive exports
( ) Standard DOS EXE [ ] Compress debug info
( ) Overlaid DOS EXE
( ) Windows EXE Code Pack Size 8192
(•) Windows DLL Segment Alignment 512
--------------------------
В Options->Linker->Libraries
Libraries Container Class Library
[X] Graphics library (•) None
[ ] Turbo Vision ( ) Static
( ) Dynamic

ObjectWindows Library Standard Run-time Libraries
(•) None ( ) None
( ) Static (•) Static
( ) Dynamic ( ) Dynamic
----------------
В Options->Librarian
Options
[ ] Generate list file
[ ] Case sensitive library
[ ] Purge comment records
[ ] Create extended dictionary

Library Page Size 16
--------

Вот.
Неизвестный
14.12.2010, 14:04
общий
Адресаты:
и Паскаль говорит: Invalid EXTRN definition (sin).

Покажите строки из ASM как выглядит определение sin.
Неизвестный
14.12.2010, 14:43
общий
Адресаты:
И еще включите "Automatic far data" компилятору C.
давно
Профессионал
304622
583
14.12.2010, 19:17
общий
И еще включите "Automatic far data" компилятору C.


Включил

Покажите строки из ASM как выглядит определение sin.


Для успешной компиляции включаю Options->Application на DOS standard.
Приведу, пожалуй, весь asm файл. Он небольшой.

Код:

.386p
ifndef ??version
?debug macro
endm
publicdll macro name
public name
endm
endif
?debug V 300h
?debug S "ASD.C"
?debug C E986998E3D054153442E43
?debug C E9644B5E3514453A5C42435C494E434C5544455C4D4154482E48
?debug C E9644B5E3515453A5C42435C494E434C5544455C5F444546532E48
_TEXT segment byte public use16 'CODE'
_TEXT ends
DGROUP group _DATA,_BSS
assume cs:_TEXT,ds:DGROUP
_DATA segment word public use16 'DATA'
d@ label byte
d@w label word
_DATA ends
_BSS segment word public use16 'BSS'
b@ label byte
b@w label word
_BSS ends
_TEXT segment byte public use16 'CODE'
?debug C E801054153442E4386998E3D
;
; double pascal qwe(double d)
;
?debug L 3
assume cs:_TEXT
QWE proc near
?debug B
push bp
mov bp,sp
?debug C E601640F0A040000
?debug B
;
; {
; return sin(d)+100;
;
?debug L 5
fld qword ptr [bp+4]
sub sp,8
fstp qword ptr [bp-8]
fwait
call near ptr sin
add sp,8
fadd dword ptr DGROUP:s@
jmp short @1@58
@1@58:
;
; }
;
?debug L 6
pop bp
ret 8
?debug C E601640F0A040000
?debug E
?debug E
QWE endp
?debug C E9
?debug C FA00000000
_TEXT ends
_DATA segment word public use16 'DATA'
s@ label byte
db 0
db 0
db 200
db 'B'
_DATA ends
_TEXT segment byte public use16 'CODE'
_TEXT ends
public QWE
extrn sin:near
?debug C EA0101
?debug C E318000000230F0100
?debug C EC03515745181800
?debug C E319000000230F0000
?debug C EB0373696E1900
end
Неизвестный
14.12.2010, 20:54
общий
Адресаты:
У Вас синус описан как near, а должен быть как far:
Код:
extrn   sin:near


Попробуйте поменять near на far в трех местах в этом коде вручную и создать obj и передать линковщику.
давно
Профессионал
304622
583
14.12.2010, 21:43
общий
Нет. По прежнему пишет
"Invalid EXTRN definition (SIN)"

(Правда sin на этот раз написал заглавными буквами. Я попробовал вручную поменять sin на SIN -- не помогло, пишет то же самое.)
Неизвестный
15.12.2010, 07:00
общий
Адресаты:
Вам какие-то конкретные функции нужно портировать в Паскаль?
Только SIN или еще что-то? Только математические?
давно
Профессионал
304622
583
15.12.2010, 13:41
общий
Только математические. Оказалось, что сам синус не нужен. Нужны:
atan
asin
acos
log
exp
sqrt
Неизвестный
15.12.2010, 14:28
общий
Адресаты:
А как Вы подключаете OBJ файл к текущему проекту на Паскале? Можно увидеть команду с параметрами запуска, а также сам исходный код на Паскале?
Неизвестный
15.12.2010, 14:45
общий
Адресаты:
Как вариант, можно на C++ написать свои указанные функции, если не требуется высокое быстродействие.
Функции можно представить разложением в ряд Маклорена с нужной точностью, думаю Вам сверхточность не нужна, поэтому можно обойтись несколькими членами ряда. Вот здесь можно взять пример (кстати там уже часть Ваших функций разложены в ряд): http://ru.wikipedia.org/wiki/%D0%A0%D1%8F%D0%B4_%D0%A2%D0%B5%D0%B9%D0%BB%D0%BE%D1%80%D0%B0
давно
Профессионал
304622
583
15.12.2010, 14:49
общий
Код:

function qwe(r:double):double;external;

{$L asd.obj}

begin
writeln(qwe(3));
readln
end.


Без обращения в asd.c к внешним функциям всё работает.
Неизвестный
15.12.2010, 14:56
общий
Адресаты:
Рассмотрите мое предложение в посте №21. Очень неплохой вариант...
давно
Профессионал
304622
583
15.12.2010, 15:47
общий
Да, я понял. Наверно, сейчас можно повести итог, что возможности привязать вызовы внешний функций в паскалевской программе нет. Можно остановиться на полученном: опции копилятора, исправляющие имена своих функций, и реализация atan и т.д. через разложение в ряд.

Вам, наверно, стоит переформулировать ответ -- он ведь будет публиковаться.
Неизвестный
15.12.2010, 19:18
общий
Так как у меня пока нет возможности редактировать свои ответы, прошу это сделать Модераторов.

Решение проблемы №1: Для того, чтобы имена собственных функций экспортировались в объектный файл в том виде, в каком они присутствуют в исходном коде программы, необходимо добавлять в определении функции ключевое слово pascal, например:
Код:
double pascal qwe(double d)

Решение проблемы №2: Для передачи в программу на Паскале функционала математических функций, таких как sin, cos, log, exp и т.д. при невысоких требованиях к производительности, данные функции проще всего реализовать в исходной программе на C путем вычисления суммы N членов ряда Тейлора, в который можно разложить указанные функции. На практике достаточно 3-4 членов ряда.
Разложение в ряд с примерами описано здесь: http://ru.wikipedia.org/wiki/%D0%A0%D1%8F%D0%B4_%D0%A2%D0%B5%D0%B9%D0%BB%D0%BE%D1%80%D0%B0

Просьба дополнить к существующему моему ответу, т.к. тот вариант ответа, который есть сейчас, тоже верный, просто мы не довели дело до конца с ним.
Неизвестный
15.12.2010, 19:46
общий
Дополнил ответ.
Форма ответа