This sample demonstrates a call to C functions from within a SAS® DATA step. The capability to call a C function from within a DATA step provides several benefits:
The Full Code tab contains the SAS code that is necessary to execute this sample in SAS. That tab also contains instructions that need to be followed in order for the example to run. There is a file on the Downloads tab that you must download, and there is a root path macro variable that you must specify in order to execute the sample code. The Output tab contains the SAS log output that is generated upon a successful run of the code.
While the SAS code contains brief commentary that describes each step, a more detailed explanation of the code follows.
The code begins with preliminaries. After you download the ranmtnrm.dll file from the Downloads tab, you need to set the ROOT macro variable to the path where you stored the ranmtnrm.dll file. Then, you need to assign the LIB library to the same location to provide a place to store files that will be created later in the example. The ranmtnrm.dll file is a C function library that contains random-number generator functions. Use the SEED macro variable to specify a seed for the random-number generator functions.
Now, you must define the prototypes using the PROTO procedure, as shown in the following SAS code. The prototypes are a SAS syntax form of the function declarations that are contained in the header files for the C functions. They consist of the function names and the parameter types for each function.
In this section of code, SAS uses the PACKAGE= option to store the prototypes in a function package within a SAS data set file. Syntax for the PACKAGE= option is as follows:
PACKAGE=library.data_set.function_packageThe STDCALL option is also necessary if the Dynamic Link Library (DLL) is compiled using the __STDCALL convention. The LINK statement links SAS to the DLL that contains the C functions. The C functions in ranmtnrm.dll are GENRAND, RANMTNRM, and SGENRAND.
A SAS DATA step calls functions that have been defined using the FCMP procedure, and PROC FCMP can call functions that have been set up using PROC PROTO. However, the DATA step cannot directly call functions that have only been set up using PROC PROTO. Thus, an intermediate step is necessary, as shown in the following SAS code:
In this intermediate step, wrapper functions are defined using PROC FCMP. The DATA step then calls these wrapper functions, which will in turn call the functions that have been set up using PROC PROTO. It is necessary to wrap all PROTO functions inside FCMP functions because the DATA step does not support C data types. The DATA step only supports double and char data types. PROC FCMP supports all C data types; thus, wrapper functions are used for automated and user-defined conversions of SAS data types to or from C data types.
PROC FCMP uses the INLIB= option to specify the SAS data set that contains the function package in which the prototypes are stored. Syntax for the INLIB= option is as follows:
INLIB=library.data_set
The OUTLIB= option specifies the function package in which to store the wrapper functions. Syntax for the OUTLIB= options is as follows:
OUTLIB=library.data_set.function_package
You can use the CMPLIB= system option in the OPTIONS statement to add the SAS data sets that contain the function packages to the search path.
SAS uses this search path to locate the functions once they are called from within a DATA step.
You can now call the wrapper functions from within the DATA step code. The functions in this sample return uniformly distributed (GENRAND) and normally distributed (RANMTNRM) random numbers based on the seed that is specified by the SEED macro variable. The following DATA step calls these functions and then prints their returned values to the SAS log. See the Output tab for the results.
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.
The following code demonstrates a call to C functions from within a DATA step.
Note: Prior to running this code, you must download the ranmtnrm.dll file from the Downloads tab, and you must set the ROOT macro variable that is specified in the code to the path where the ranmtnrm.dll file is stored on the file system.
/* Specify the storage location of the ranmtnrm.dll file */
%let root = C:\temp;
/* Define the library in which to store the SAS data set that contains */
/* the functions that are declared using the PROTO procedure. */
libname lib "&root";
/* Specify a seed value for the random-number generator functions. */
%let seed=1;
/* Use PROC PROTO to define the library, data set, and function */
/* package in which to store the function prototypes. */
proc proto package=lib.Proto_ds.ranmtnrm
label="Random Number Generators"
stdcall;
/* Link SAS to the DLL that contains the compiled C functions. */
link "&root\ranmtnrm.dll";
/* Declare the function prototypes. */
double genrand(void) label="Uniform random number generator";
double ranmtnrm(void) label="Normal random number generator";
void sgenrand(unsigned long seed) label="Initialize seed value";
run;
/* Use the FCMP procedure to wrap the C functions calls so that they */
/* can be used in the DATA step. Specify which SAS data set to read */
/* that contains the function package with the function prototypes, */
/* and specify the function package in which to store the wrapper */
/* functions that are being defined in this FCMP step. */
proc fcmp inlib=lib.Proto_ds
outlib=lib.FCmp_ds.ranmtnrm;
/* Define a wrapper function for each of the C functions. */
subroutine sas_sgenrand(seed);
call sgenrand(seed);
endsub;
function sas_genrand();
x1=genrand();
return(x1);
endsub;
function sas_ranmtnrm();
x2=ranmtnrm();
return(x2);
endsub;
quit;
/* Specify the search path for the function packages that were */
/* created with the PROTO and FCMP procedures so that SAS knows */
/* where to find them when the functions are used. */
options cmplib=(lib.Proto_ds lib.FCmp_ds);
/* Call the C functions from within the DATA step and print the results */
/* to the log window. */
data _null_;
call sas_sgenrand(&seed);
x1 = sas_genrand();
call sas_sgenrand(&seed);
x2 = sas_ranmtnrm();
put "--------------------";
put "PROTO Function Calls";
put "--------------------";
put "For seed = &seed";
put "GENRAND returns: " x1;
put "RANMTNRM returns: " x2;
put "--------------------";
run;
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.
The following output is printed to the SAS log:
-------------------- PROTO Function Calls -------------------- For seed=1 GENRAND returns: 0.8838658645 RANMTNRM returns: 1.0120214427 --------------------
Download the following file prior to running the sample SAS code that is provided with this example.
Note that the following ranmtnrm.dll file is compiled as a 32-bit Windows application. The bitness between SAS and the compiled C library must be the same (for example, both 32-bit or both 64-bit). Therefore you can only call the following ranmtnrm.dll file from 32-bit SAS.
Type: | Sample |
Topic: | SAS Reference ==> Procedures ==> FCMP SAS Reference ==> DATA Step SAS Reference ==> Functions ==> External Routines |
Date Modified: | 2014-07-15 10:43:49 |
Date Created: | 2008-05-12 18:47:59 |
Product Family | Product | Host | SAS Release | |
Starting | Ending | |||
SAS System | Base SAS | Microsoft Windows Server 2003 Standard Edition | 9.2 TS1M0 | |
Microsoft Windows Server 2003 Enterprise Edition | 9.2 TS1M0 | |||
Microsoft Windows Server 2003 Datacenter Edition | 9.2 TS1M0 | |||
Microsoft Windows 2000 Professional | 9.2 TS1M0 | |||
Microsoft Windows 2000 Server | 9.2 TS1M0 | |||
Microsoft Windows 2000 Datacenter Server | 9.2 TS1M0 | |||
Microsoft Windows 2000 Advanced Server | 9.2 TS1M0 | |||
Microsoft® Windows® for x64 | 9.2 TS1M0 | |||
Microsoft Windows XP 64-bit Edition | 9.2 TS1M0 | |||
Microsoft Windows Server 2003 Enterprise 64-bit Edition | 9.2 TS1M0 | |||
Microsoft Windows Server 2003 Datacenter 64-bit Edition | 9.2 TS1M0 | |||
Microsoft® Windows® for 64-Bit Itanium-based Systems | 9.2 TS1M0 | |||
Windows Vista | 9.2 TS1M0 | |||
Microsoft Windows XP Professional | 9.2 TS1M0 |