C routine processing
On Windows and Unix, a C routine is referenced as if it were declared as follows:
INT_REG c_routine(DESCRIP *argblk[])
where argblk is the controlling argument block. The return value depends on whether or not c_routine was declared as a ^VAL function in the calling routine:
- If c_routine was not declared as a ^VAL function in the calling routine, the return value is one if the routine completed successfully, or some other system-specific value if it did not complete successfully. (This value is the same as that obtained by the calling routine when the DBL$XSTAT subroutine is used on OpenVMS.)
- If c_routine was declared as a ^VAL function in the calling routine, the return value is the actual result of the routine’s processing.
INT_REG is defined in machine.h as the largest value on the machine that can hold a pointer.
Data is maintained within the Synergy DBL environment by descriptor and is passed to and from routines using descriptor pointers within the argument block. If the C routine is called with a subroutine, or with a function reference that was declared as a ^VAL function in the calling routine, ((INT_REG)argblk[0]) is the actual number of arguments passed, argblk[1] points to the descriptor of the first actual argument, argblk[2] points to the descriptor of the second actual argument, and so forth. (For more information, see ^VAL.)
If the C routine is being called with a function reference that was not declared as a ^VAL function in the calling routine, ((INT_REG)argblk[0]) is one greater than the actual number of arguments passed, argblk[1] points to the descriptor of an automatically created return value field, argblk[2] points to the first actual argument’s descriptor, argblk[3] points to the second actual argument’s descriptor, and so on.
Note that the called routine is responsible for loading the return value field. If an argblk entry is null, the associated actual argument was not passed. If entry n within argblk was generated with a ^REF(variable), ((void *)argblk[n]) is a pointer to variable’s data. If entry n in argblk was created using a ^VAL(expression) function, ((INT_REG)argblk[n]) is the evaluated value of expression.
Many of the data types and storage mechanisms are incompatible between Synergy DBL and C. In Synergy DBL, for example, alpha data is not null-terminated, and space for an alpha function’s return value is not allocated until data is stored.
For these reasons, among others, you should use the Synergy DBL C Interface routines exclusively whenever you’re accessing Synergy DBL data. Your data or memory could become corrupted if you don’t. |
The above warning doesn’t apply to arguments that were generated using either a ^VAL or ^REF function. An argblk entry is a native CPU (void *) pointer for ^REF and a native CPU (long) integer for ^VAL. In such cases, it is your responsibility to access the argument block and any related data in a manner that is compatible with Synergy DBL.
Be careful when a ^REF to an integer is passed. Unless the data has been aligned using the .ALIGN compiler directive, the referenced integer probably doesn’t lie on a natural int boundary. This situation can cause access violations in some environments and considerably slower access in others.
For Synergy DBL access of memory allocated in a C subroutine, either as variables or malloc, we recommend using ^M memory handles.
On Unix, do not use signal() in your C code; use the newer sigaction routine. Use of signal will cause random and catastrophic errors at runtime. |