[Openmcl-devel] Accessing foreign #define'd constants

Gary Byers gb at clozure.com
Thu Dec 23 00:13:54 UTC 2004

On Wed, 22 Dec 2004, David Steuber wrote:

> On Dec 22, 2004, at 12:46 PM, Denis Bueno wrote:
> > The problem was that what I had assumed was a C constant was actually
> > a #define'd C macro ... so of course I couldn't call it.
> Right.  #define is simply a text substitution.  I don't know if I am
> comfortable calling them C macros ;-)
> > I know it's not the responsibility of the openmcl documentation to
> > teach people C, but, maybe a little note (in sec. 9.8?) about the
> > preferred way to have openmcl call C macros (like by making "glue" via
> > a my_macro_call.c file with a my_macro_call() function and calling
> > that function from openmcl, or something) would be helpful to anyone
> > who runs into this problem in the future. I'm certainly willing to
> > write it, if that is acceptable.
> The Carbon headers make a lot of use of enums for C constants.  These
> have the advantage of being real constants that are also available via
> #$.  What I hate though is the frequent practice of enums that are
> assigned like this:
> foo = 'ctrl',
> Joy!  At least #$ works.  When the same thing is a #define...  Well
> then you have to figure out what the UInt32 that is.

Here's a little-known (perhaps because it's undocumented ...) fact:
if the reader token that follows #$ is a quoted string of length 4,
#$ produces an integer constant out of the char-codes, so:

Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-p1!
? #$"ctrl"
? (format t "#x~x" *)

In most cases, #$ can be used to reference constants that were defined

#define <name> <expression>

whether or not this works generally has to do with how complicated the
C code in <expression> is.  There's no requirement that the right-hand
part of the #define - what I'm calling the <expression> - is even well-
formed C code.  If it looks like it is, OpenMCL's interface translator
will try to parse and evaluate it; it's able to do a fairly good job
of this in practice, but undoubtedly misses some things.  It -does-
try to catch cases like:

#define FOO 1
#define BAR (FOO + 17)

and will make multiple passes to try to resolve forward references

#define BAR (FOO + 17)
#define FOO 1

C macros can also take parameters, as in:

#define MAX(a,b) (a) > (b) ? (a) : (b)

The interface translator ... um, assumes that this is some sort of
irritating line noise and skips over it (trying to translate arbitrary
parameterized C macros into "equivalent" Lisp macros is a hard problem).

The interface translator should do a very good job of making constants
defined as part of a C enumeration available to #$, and should catch
a lot of cases where constants are defined via '#define <name> <expr>';
its success in doing so generally depends on how much sense it can
make out of <expr>.

I'd be curious about cases where #$ doesn't find things; it's been a
while since I checked, but I think of the translator's miss rate as
being pretty low.  (It's certainly possible that the Carbon headers
use C idioms that the translator doesn't understand, and - depending
on what they are - it might be possible to make it understand them.)

> Bottom line though is when you are using FFI to call into C (and having
> C call back!), it really does help to know some C.

That's certainly true.  I -think- that it's true that the total number
of idioms you have to learn in order to translate a C example program
into OpenMCL's FFI is fairly small, but the learning curve could probably
be made less steep with a few examples.

More information about the Openmcl-devel mailing list