开发者

Connect SAS to a C library

This is related to calling C functions (made into dynamic libraries) from SAS. There are 4 files. the first 2 (1 c-file and 1 sas-file) are a positive control using doubles. The remaining files are the problematic.

C-FILE-1

#ifdef BUILD_DLL  
#define EXPORT __declspec(dllexport)  
#else  
#define EXPORT __declspec(dllimport)  
#endif  
#include "stdio.h"  
#include "stdlib.h"  
#include "string.h"  

EXPORT void test (double *inarray, double *outarray, int n)  
{    
int i;   
 for (i=0; i<n;i++)  
   {  
     outarray[i]= inarray[i]*2;  
   }  
 return;  
}  

//gcc -c -DBUILD_DLL pointersVoid.c

//gcc -shared -o pointersVoid.dll pointersVoid.o

SAS-FILE-1

filename sascbtbl catalog 'work.api.MYFILE';  
data _null_;  
    file sascbtbl;  开发者_StackOverflow
    input;  
    put _infile_;  
    cards4;  
    routine test  
    module=pointersVoid    
    minarg=3  
    maxarg=3;  
arg 1 input num byvalue format=IB4.;  
arg 2 input num byvalue format=IB4.;  
arg 3 input num byvalue format=PIB4.;  
;;;;  
run;  
data test;  
  array arr(5)  _temporary_  (7.56 2.356 63.54 5.14 8.2);  
  array ret(5);  
    rc=modulen ("*e","test",addr(arr(1)), addr(ret(1)), 5);  
run;  

This works fine and ret array now contains the *2 of the original values. But when we use strings we get errors:

C-FILE-2

#include "stdio.h"  
#include "stdlib.h"  
#include "string.h"  

char *strtrim_right(char *p)  
{  
    char *end;  
    int len;  
    len = strlen(p);  
    while (*p && len)  
    {  
        end = p + len-1;  
        if(isalpha(*end))  
            *end = 0;  
        else  
            break;  
        len = strlen(p);  
    }  
    return(p);  
}  

EXPORT char **test (char **x, char **y, int n)  
{  
    int i;  
    for (i = 0; i < n; i++)  
    {  
        y[i] = strtrim_right(x[i]);
    }
}

/*
gcc -c -DBUILD_DLL pointers-array-string-void.c  
gcc -shared -o pointers-array-string-void.dll pointers-array-string-void.o   
*/

SAS-FILE-2

filename sascbtbl catalog 'work.api.MYFILE';  
data _null_;  
    file sascbtbl;  
    input;  
    put _infile_;  
    cards4;  
    routine test  
    module=pointers-array-string-void  
    minarg=3  
    maxarg=3;  
arg 1 input char byvalue format=$CSTR200. ;  
arg 2 input char byvalue format=$CSTR200. ;  
arg 3 input num byvalue format=PIB4. ;  
;;;;  
run;  
data test;  
    array arr(5) $ _temporary_ ('PM23RO' '85AB12RE' 'RE147AMF' 'TAGH14MMF' 'LCA2Q');  
    array ret(5) $;  
    call module ("*e","test",addr(arr(1)), addr(ret(1)), 5);  
run;  

This doesn't work and gives errors:

Unrecognized option - in ROUTINE statement
NOTE: Invalid argument to function MODULE
ret1=  ret2=  ret3=  ret4=  ret5=  rc=. _ERROR_=1 _N_=1

I know the C-FILE-2 works well because the dll has been tested from another aplication, so ther error source is very likely the SAS code in SAS-FILE-2. Any suggestions to make it work?


In 64-bit SAS you will want to use addrlong and update the module parameter declarations to have format=$ptr. datalen=8.

If your .dll is 32 bit you should still be able to invoke its routines by adding the routine declaration option dlltype=32. ("When I'm 64-bit: How to Still Use 32-bit DLLs in Microsoft Windows" Rick Langston, SAS Global Forum 2015.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜