translate a macro to D

Steven Schveighoffer schveiguy at yahoo.com
Mon Jul 11 07:02:38 PDT 2011


On Mon, 11 Jul 2011 09:21:53 -0400, teo <teo.ubuntu at yahoo.com> wrote:

> On Fri, 08 Jul 2011 09:54:40 -0400, Steven Schveighoffer wrote:
>
>> On Thu, 07 Jul 2011 16:23:33 -0400, teo <teo.ubuntu at yahoo.com> wrote:
>>
>>> On Thu, 07 Jul 2011 11:57:51 -0400, Steven Schveighoffer wrote:
>>>
>>>> Well, I can't really say I understand the point of using this macro at
>>>> all.  sizeof is a builtin, and part of the C spec.  Why not just use
>>>> sizeof?
>>>>
>>>>
>>> Well, have a look please at ioctl.h (linux). You will find the
>>> following macros:
>>>
>>>
>>> #define _IOC(dir,type,nr,size) \
>>>         (((dir)  << _IOC_DIRSHIFT) | \
>>>          ((type) << _IOC_TYPESHIFT) | \
>>>          ((nr)   << _IOC_NRSHIFT) | \
>>>          ((size) << _IOC_SIZESHIFT))
>>>
>>> #define _IOC_TYPECHECK(t) (sizeof(t))
>>>
>>> /* used to create numbers */
>>> #define _IO(type,nr)            _IOC(_IOC_NONE,(type),(nr),0) #define
>>> _IOR(type,nr,size)
>>> _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK (size)))
>>> #define _IOW(type,nr,size)      _IOC(_IOC_WRITE,(type),(nr),
>>> (_IOC_TYPECHECK(size)))
>>> #define _IOWR(type,nr,size)     _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),
>>> (_IOC_TYPECHECK(size)))
>>>
>>>
>>> This is what I am after. However I thought that a simplified case will
>>> make it easier to describe the problem.
>>>
>>>
>> Hm... I once wrote a D module that accessed a linux device driver (ipmi
>> driver to be specific).  I did it in D1, and I used CTFE.  For sure,
>> t.sizeof should work instead of _IOC_TYPECHECK.  But Linux supports a
>> multitude of CPUs, perhaps other CPUs need a different macro for this.
>> It's the only thing I can think of to explain having a specific macro to
>> do sizeof.
>>
>> -Steve
>
>
> Steve,
>
> I translated those macros to regular functions and it works that way
> (using T.sizeof), however I could have used a function template instead
> as you suggested before and therefore I have a question:
>
> Are there any benefits of using function templates instead of regular
> functions in that particular case?
> The above leads me to another question: are those functions evaluated at
> compile-time? I suppose they are not.

I think you may be confusing function templates with plain templates?  I  
remember suggesting this:

template MM(uint a, uint b, T)
{
   enum MM = (a << SHIFT_A) | (b << SHIFT_B) | (T.sizeof << SHIFT_SIZE);
}

which is *not* a function template, it's simply a template which evaluates  
to an enum.

The advantage is, no matter where you use it, it is done at compile time.   
For something like ioctl constants, this is important.

Let's take a simple example:

myconstant(uint x)
{
    return x << 5;
}

Now, if you use it in some code:

ioctl(myconstant(2), ...);

In a standard build (i.e. without any switches), the call to myconstant is  
made, and the shift is performed, even when the value is easily known at  
compile time.  Essentially you have wasted cycles computing the myconstant  
result.  If you have both optimization (-O) and inlining (-inline), this  
might result in the correct constant being sent to ioctl, but there is a  
better way...

If we simply wrap myconstant into a template enum:

template myconstantCT(uint x)
{
    enum myconstantCT = myconstant(x);
}

myconstantCT is evaluated at compile time, and replace with the exact  
number wherever you use it.  This happens regardless of compiler switches:

ioctl(myconstantCT!2, ...)

This always results in simply passing a number to ioctl.

So the benefit of using a template enum to do parameterized constants is  
that it guarantees compile time evaluation.  This is a perfect fit for  
IOCTL constants which never change.

-Steve


More information about the Digitalmars-d-learn mailing list