Τρίτη, 11 Απριλίου 2017

Χρήση Ρουτίνας C με πέρασμα τιμών με αναφορά!


Σε αυτό το παράδειγμα (πάλι στα αγγλικά), έχω μια απλή συνάρτηση σε c που παίρνει τέσσερις παραμέτρους, οι δυο όμως τελευταίοι είναι δείκτες σε διπλό (δηλαδή σε κινητής υποδιαστολής διπλής ακριβείας - 8 byte) και το ζητούμενο είναι να μας επιστρέψει σε αυτές τα αποτελέσματα.
Αυτό μπορεί να γίνει επειδή οι διαρθρώσεις μνήμης (Διάρθρωση ή Buffer) ορίζουν μνήμη και παρέχουν διευθύνσεις για το σκοπό αυτό.
Υπάρχουν δυο τμήματα, το ένα φτιάχνει το dll, και το άλλο το χρησιμοποιεί. Το πρώτο χρειάζεται να τρέξει μια μόνο φορά. Σε αυτό το  παράδειγμα το αρχείο c το εξάγω UTF-8 (η εντολή Save.Doc βάζει και το BOM τον χαρακτήρα αναγνώρισης φορμά και έτσι το διαβάζει ο gcc, δοκίμασα τα 0 και 1 για UTF-16LE και UTF-16BE και δεν βγάζει Object file, ενώ με την επιλογή 3, ascii αρχείο παίζει, όπως το έδειναν και οι εντολές για αρχεία Open/Close στην έκδοση για Ascii - υπάρχει και για Unicode αλλά μόνο για UTF-16LE. Να σημειώσω εδώ ότι και τα αρχεία προγραμμάτων της Μ2000 σώνονται ως UTF-8)

Παίζει και η παραλλαγή με struct στην C
βάζουμε το κώδικα παρακάτω
      c_code$={
            #include <math.h>
            struct xycoord { double x, y; };
            polar_to_rectangular(double rho, double theta, struct xycoord *cp)
                  {
                   cp->x = rho * cos(theta);
                   cp->y = rho * sin(theta);
                  }

            }


Παραμένει το Declare στην συντομογραφία με τις τελείες ...
      Declare polar lib c "c:\MyRef.polar_to_rectangular" { ... }
 Και το Call που δίνει το Structure της Μ2000  (το ! παιρνάει την τιμή ως Long)

      Call Void polar(rho,theta, !A(0))



Module MakeDll {
      \\ This code used to show how to pass parameters by reference in c
      \\ so our task is to use it from M2000
      \\ in previous example we see how to pass an array
      \\ we use a structure and a buffer for it to get pointers and pass them to c function in a dll.
      c_code$={
            #include <math.h>
            polar_to_rectangular ( double rho, double theta , double *xp, double *yp )
                      {      
                       *xp = rho * cos(theta);
                       *yp = rho * sin(theta);
                        };
            }
      Module Make ( fname$, code$, timeout ) {
            if timeout<1000 then timeout=1000
            If left$(fname$,2)="My" Else Error "Not proper name - use 'My' as first two letters"
            Dos "del  c:\"+fname$+".*", timeout;
            Document code$ \\ upgrade to document to export as UTF-8 using 2 - or 3 for ascii
            Save.Doc code$, "c:\"+fname$+".c", 2
            \\ use these two lines for opening dos console and return to M2000 command line
            rem : Dos "cd c:\ && gcc -c -DBUILD_DLL "+fname$+".c"
            rem : Error "Check for errors"
            \\ by default we give a time to process dos command and then continue
            dos "cd c:\ && gcc -c -DBUILD_DLL "+fname$+".c" , timeout;
            if exist("c:\"+fname$+".o") then {
                  dos "cd c:\ && gcc -shared -o "+fname$+".dll "+fname$+".o -Wl,--out-implib,libmessage.a", timeout;
            } else Error "No object file - Error"
            if not exist("c:\"+fname$+".dll") then Error "No dll - Error"
      }
      Make "MyRef", c_code$, 1000
}
Module UseDll {
      \\ using Long for pointers
      \\ rho and theta has no type here (only type Long recognize the Declare command)
      \\ also we can place ... which means any number of parameters
      Rem : Declare polar lib c "c:\MyRef.polar_to_rectangular" { rho, theta, long xp, long lyp}
   
      \\ we can push long using ! before an expression, so we can remove long from declare
      Rem : Declare polar lib c "c:\MyRef.polar_to_rectangular" { rho, theta, xp, lyp}
      \\  we use here ... as any number of parameters - so we have to use ! for Long values
      Declare polar lib c "c:\MyRef.polar_to_rectangular" { ... }
      Structure pol {
            xp as double
            yp as double
      }
      Buffer Clear A as pol
   
      \\ lambda funsctions capture Buffers and Structures by refeference (pointer)
      \\ A(0) is the address of first item (we have one item as pol)
      \\ pol("xp") is 0 and pol("yp) is 8
      \\ so we can use A(0) and A(0)+8
      \\
      addr=Lambda A, pol (offset$)->A(0)+pol(offset$)
      rho=100
      theta=pi/16
      \\ Calculate using C
      \\ using Void to drop any return from C call
      \\ if return is non zero then an error occur in M2000, for Call command
      \\ ! means pass an expression as long
      \\ We give pointer if long contain address from Buffer. Anything other means abnormal operation
      Rem : Call Void polar(rho,theta, !A(0)+pol("xp") , !A(0)+pol("yp"))
   
      Call Void polar(rho,theta, !addr("xp") , !addr("yp"))
   
      \\ Calculate using M2000 (we get same result from both languages)
      \\ using @(20) to move cursor at 21 position from left
   
      Print rho * cos(theta*180/pi), @(20), rho * sin(theta*180/pi) \\ cos and sin in degrees in M2000
   
      \\ results
      \\ from Buffer using offsets
   
      Print eval(A, 0!xp), @(20), eval(A, 0!yp)
   
      \\ second type for reading, offset in bytes and type to peek from address
   
      Print eval(A, pol("xp") as double), @(20),eval(A, pol("yp") as double)
   
      \\ we can change values using Return to Buffer command
   
      Return A, 0!xp:=-1.5, 0!yp:=30.12
      Print "Show changed values"
      Print eval(A, 0!xp), @(20), eval(A, 0!yp)
}
Rem :
MakeDll   \\ join this line to "Rem :" above after first time!
\\ so now we can use the dll
Usedll