Overview
This sample provides step-by-step instruction and guidance through the process of defining your own
function in C, compiling your C code, and then calling your C function from within a SAS DATA step.
It is assumed that you are familiar with programming in C and compiling C source code.
The steps for defining a C function and calling it from SAS are as follows:
- Define a function in C.
- Compile the C source code into a shared library.
- Perform a test call to the function from C.
- Link SAS to the shared library with the PROTO procedure.
- Define a SAS function with the FCMP procedure.
- Store the SAS function as a compiled routine.
- Call the function with DATA step.
Details
The C function can be written in an editor of your choice, such as VI Editor or Microsoft Windows Notepad.
This sample contains C source code for a function called
myfactorial that computes the factorial of an
integer:
int myfactorial(int n){
int i;
int p;
for(p=1, i=2; i<=n; p=p*i, i++);
return p;
}
Note that you might need to modify your C source code based upon which compiler you use.
The C program above is stored on the
Downloads tab for this sample, and
the program is named myfactorial.c.
In order for SAS to be able to use a C program, the C source code must be compiled into a shared library.
Note that shared libraries are platform specific. For instance, a shared library that is compiled in an
AIX operating environment is not compatible with a Windows platform. You should consider each of the
following factors when you compile C source code:
- Operating system (Examples: Windows, AIX, Solaris, and Linux)
- CPU architecture (Examples: 32-bit and 64-bit)
- Compiler (Examples: GCC and Microsoft Visual C++)
- Operating system version (Examples: Windows versions are 7, Vista, and XP)
- Compiler version (Examples: GCC versions are 4.5.1, 4.2.0, and 3.3.4)
These factors are especially important if your shared library is to be used on a machine other than the
one on which it was compiled. Differences can result in an incompatibility for the shared library.
There are several different C compilers. The configuration steps and command-line syntax that are
required to compile your C source code is dependent upon which C compiler you use. For example,
you can use the following command-line syntax to compile the myfactorial.c program
via the GCC 4.2.0 compiler on an AIX 5.3 64-bit platform:
gcc -maix64 -c -Wall -ansi -g -fPIC myfactorial.c
gcc -maix64 -shared -o myfactorial.so -fPIC myfactorial.o
The resulting myfactorial.so file is a shared library that can then be used by SAS.
As another example, you can use the following configuration steps to compile the myfactorial.c
program via Microsoft Visual Studio 2010 in the Windows 7 operating environment:
- Create a new Visual C++ empty project.
- Add myfactorial.c as a source file to the project.
- Add myfactorial.def as a source file to the project, where myfactorial.def contains the following
code:
LIBRARY "myfactorial"
EXPORTS
myfactorial @1
- Edit the following project configuration properties in the Visual Studio 2010 Properties Pages
window:
- Select General in the navigation tree in the left pane of the Properties
Pages window.
- In the right pane, select Configuration Type, which displays a list. From that list,
select Dynamic Library (.dll).
- Click the Apply button. You must click Apply in order to edit
the next properties.
- In the left pane, select C/C++.
- Under C/C++, select Code Generation.
- In the right pane, select Runtime, which displays a list. From that list select
Multi-Threaded (/MT).
- In the left pane under C/C++, select Advanced.
- In the right pane, select Calling Convention, which displays a list. From that list,
select __stdcall (/Gz).
- Click the OK button
- Build the solution.
Notice the use of the definition file. As noted in the
LINK statement section of the
PROTO procedure documentation, many compilers do not export function names by default. An external declaration
of the function in the C source code using
_declspec(dllexport)
is one way to accomplish this, and a definition file is another way to export the function names. The export program above is stored on the
Downloads tab for this sample, and it is named myfactorial.def.
In addition to exporting function names, you might need to incorporate other modifications into your C
source to account for features that vary according to the compiler that you use. For example, some
compilers perform name mangling of the functions during the source code compilation. For more specific
details on the configuration steps and syntax to use for your compiler, see the user manual for your
compiler.
This step is optional, but it is recommended. If you are not able to call your C function directly from C,
outside of SAS, then there is a strong likelihood that a call to the function from within SAS also will fail.
The following C test program calls the myfactorial
function with an input argument of 6:
#include <stdio.h>
int main(int argc, char** argv) {
int n=6;
int out;
out=myfactorial(n);
printf("%d\n",out);
return (0);
}
This test program is stored on the
Downloads tab for this sample, and it is named
testmyfactorial.c. You can use the following command-line syntax to execute the testmyfactorial.c test
program to call the
myfactorial function in the
myfactorial.so shared library via the GCC 4.2.0 compiler on an AIX 5.3 64-bit platform:
gcc -maix64 testmyfactorial.c myfactorial.so
./a.out
The output is
720.
Use PROC PROTO to link SAS to the shared library that contains your C function.
Sample 32080 provides greater detail for this step and the
remaining steps, and the PROTO procedure documentation also contains relevant information. To use a C function in SAS, the corresponding shared
library needs to be linked via the LINK statement. The following SAS code links SAS to the shared library
and loads the function declarations to the Work.Proto_ds.Cfcns function package:
proc proto stdcall package=work.proto_ds.cfcns;
link 'c:\temp\myfactorial.dll';
int myfactorial(int n) ;
run;
This SAS code assumes that the myfactorial.dll shared library is stored in the
C:\temp directory. The .dll extension in the filename indicates that the shared library was compiled under Windows and
that this code is being executed in a Windows environment. The STDCALL option in the PROC PROTO statement
indicates that the myfactorial.dll shared library was compiled on a Windows 32-bit platform using the
__stdcall convention.
A successful execution of the SAS code above results in the following SAS log details:
NOTE: 'c:\temp\myfactorial.dll' loaded from specified path.
NOTE: Prototypes saved to WORK.PROTO_DS.CFCNS.
NOTE: PROCEDURE PROTO used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
A C function that is linked to SAS is only available to specific SAS procedures, such as the FCMP and COMPILE
procedures. PROC FCMP is a Base SAS® procedure, and PROC COMPILE is a SAS® Risk
Dimensions® procedure. This sample uses PROC FCMP, but the syntax for PROC COMPILE is similar.
When you use PROC FCMP, it is possible both to directly call a C function and to define a function that is
available to the DATA step and many SAS procedures. The following SAS code defines a SAS function called
sas_myfactorial that contains a call to
the myfactorial C function:
proc fcmp inlib=work.proto_ds outlib=work.fcmp_ds.sasfcns;
function sas_myfactorial(x);
return (myfactorial(x));
endsub;
quit;
This SAS code uses the INLIB= option to specify where the
myfactorial
C function information is stored, and it uses the OUTLIB= option to specify where to store the
SAS function
sas_myfactorial that is defined. A
successful execution of the SAS code above prints the following output to the SAS log:
NOTE: 'c:\temp\myfactorial.dll' loaded from specified path.
NOTE: Function sas_myfactorial saved to work.fcmp_ds.sasfcns.
NOTE: PROCEDURE FCMP used (Total process time):
real time 0.03 seconds
cpu time 0.01 seconds
Use the SAS CMPLIB= system option to specify the storage locations for the C and FCMP functions:
options cmplib=(work.proto_ds work.fcmp_ds);
Execution of this SAS statement is necessary in order for your functions to be available to other SAS
procedures and to the DATA step.
It is now possible to call your function from the DATA step. From the DATA step, you need to call the FCMP
function (sas_myfactorial in
this sample) instead of the C function. The DATA step recognizes that the
sas_myfactorial
function is available because it has been saved to a CMPLIB library. The SAS function
sas_myfactorial, in turn, calls the
myfactorial C function, which was compiled in
the myfactorial.dll shared library to which SAS was linked in the PROC PROTO step. In the following SAS code,
the argument 6 is passed to the function:
data _null_;
x=sas_myfactorial(6);
put x=;
run;
When the argument is passed to the myfactorial
C function, the calculated result is returned to the SAS function sas_myfactorial,
which is in turn passed back to the DATA step. The flow of the full process is: DATA step → FCMP → PROTO → C → FCMP → DATA step.
Upon successful execution of the SAS code above, the following note is printed to the SAS log:
NOTE: 'c:\temp\myfactorial.dll' loaded from specified path.
x=720
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.03 seconds
The resulting value of
720 is consistent with
the result that was produced from the C test program that is noted above in
Step 3.
The SAS code from the four previous steps above is stored on the Downloads tab for this
sample. That program is named myfactorial.sas.
Additional Documentation
-
SAS Institute Inc. 2009. SAS Sample 32080, "Using the PROTO procedure to call C functions from within a DATA step." Cary, NC: SAS Institute Inc. Available at
support.sas.com/kb/32/080.html.
-
SAS Institute Inc. 2007. SAS Sample 26151, "Create user-defined functions with PROC FCMP." Cary, NC: SAS Institute Inc. Available at
support.sas.com/kb/26/151.html.
-
SAS Institute Inc. 2007. "User-Written DATA Step Functions." SAS Global Forum 2007 Cary, NC: SAS Institute Inc. Available at
www2.sas.com/proceedings/forum2007/008-2007.pdf.
-
SAS Institute Inc. 2008. "CMPLIB= System Option" in SAS® 9.2 Language Reference: Dictionary, Third Edition. Cary, NC: SAS Institute Inc. Available at
support.sas.com/documentation/cdl/en/lrdict/59540/HTML/default/base-sysop-cmplib.htm.
-
SAS Institute Inc. 2008. SAS Note 31738, "SAS crashes when running PROC PROTO." Cary, NC: SAS Institute Inc. Available at
support.sas.com/kb/31/738.html.
-
SAS Institute Inc. 2008. "The FCMP Procedure" in Base SAS® 9.2 Procedures Guide. Cary, NC: SAS Institute Inc. Available at
support.sas.com/documentation/cdl/en/proc/59565/HTML/default/ a002890483.htm.
-
SAS Institute Inc. 2008. "The PROTO Procedure" in Base SAS® 9.2 Procedures Guide. SAS Institute Inc. Cary: NC. Available at
support.sas.com/documentation/cdl/en/proc/59565/HTML/default/a002890473.htm.
These sample files and code examples are provided by SAS Institute
Inc. "as is" without warranty of any kind, either express or implied, including
but not limited to the implied warranties of merchantability and fitness for a
particular purpose. Recipients acknowledge and agree that SAS Institute shall
not be liable for any damages whatsoever arising out of their use of this material.
In addition, SAS Institute will provide no support for the materials contained herein.