www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - translate a macro to D

reply teo <teo.ubuntu yahoo.com> writes:
What is the best way to translate following to D?

#define MAKELONG(a, b) \ 
    ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

The point is I would like to be able to use that at compile-time. The 
macro is supposed to define some constants.
Jul 06 2011
parent reply Trass3r <un known.com> writes:
Am 06.07.2011, 16:15 Uhr, schrieb teo <teo.ubuntu yahoo.com>:

 What is the best way to translate following to D?

 #define MAKELONG(a, b) \
     ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

 The point is I would like to be able to use that at compile-time. The
 macro is supposed to define some constants.

Just turn it into a function. If you assign it to an enum or use it as an initializer for global immutables it should be evaluated at compile-time.
Jul 06 2011
next sibling parent teo <teo.ubuntu yahoo.com> writes:
On Wed, 06 Jul 2011 16:21:31 +0200, Trass3r wrote:

 Am 06.07.2011, 16:15 Uhr, schrieb teo <teo.ubuntu yahoo.com>:
 
 What is the best way to translate following to D?

 #define MAKELONG(a, b) \
     ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

 The point is I would like to be able to use that at compile-time. The
 macro is supposed to define some constants.

Just turn it into a function. If you assign it to an enum or use it as an initializer for global immutables it should be evaluated at compile-time.

Thank you. That did the trick. However I am facing another problem: There is a macro, which obtains the size of a type #define TYPESIZE(t) (sizeof(t)) Example: printf("%ld\n", TYPESIZE(short)); printf("%ld\n", TYPESIZE(struct A)); The TYPESIZE macro is used within another macro which defines constants. #define M(a,b,size) \ ((a) << SHIFT_A) | \ ((b) << SHIFT_B) | \ ((size) << SHIFT_SIZE)) #define MM(a,b,type) M((a),(b),(TYPESIZE(type))) Example: #define C1 MM(1, 2, struct A) #define C2 MM(3, 4, struct B) How can I translate that to D?
Jul 07 2011
prev sibling next sibling parent Trass3r <un known.com> writes:
 The  TYPESIZE macro is used within another macro which defines constants.
 #define M(a,b,size) \
 	 ((a) << SHIFT_A) | \
 	 ((b)   << SHIFT_B) | \
 	 ((size) << SHIFT_SIZE))
 #define MM(a,b,type)	    M((a),(b),(TYPESIZE(type)))

 Example:
 #define C1    MM(1, 2, struct A)
 #define C2    MM(3, 4, struct B)

 How can I translate that to D?

You could just get rid of that extra macro and directly pass A.sizeof. Otherwise you need to use templates. Can't say more cause I can't imagine what the heck this code is used for.
Jul 07 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Jul 2011 11:38:05 -0400, teo <teo.ubuntu yahoo.com> wrote:

 On Wed, 06 Jul 2011 16:21:31 +0200, Trass3r wrote:

 Am 06.07.2011, 16:15 Uhr, schrieb teo <teo.ubuntu yahoo.com>:

 What is the best way to translate following to D?

 #define MAKELONG(a, b) \
     ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

 The point is I would like to be able to use that at compile-time. The
 macro is supposed to define some constants.

Just turn it into a function. If you assign it to an enum or use it as an initializer for global immutables it should be evaluated at compile-time.

Thank you. That did the trick. However I am facing another problem: There is a macro, which obtains the size of a type #define TYPESIZE(t) (sizeof(t))

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? In d it's t.sizeof.
 Example:
 printf("%ld\n", TYPESIZE(short));
 printf("%ld\n", TYPESIZE(struct A));

printf("%ld %ld\n", short.sizeof, A.sizeof);
 The  TYPESIZE macro is used within another macro which defines constants.
 #define M(a,b,size) \
 	 ((a) << SHIFT_A) | \
 	 ((b)   << SHIFT_B) | \
 	 ((size) << SHIFT_SIZE))
 #define MM(a,b,type)	    M((a),(b),(TYPESIZE(type)))

Define MM and M as normal functions as Trass3r suggested, then use type.sizeof.
 Example:
 #define C1    MM(1, 2, struct A)
 #define C2    MM(3, 4, struct B)

Note, in D, to ensure compile-time evaluation, it's useful to have a template that does this: template MM(uint a, uint b, T) { enum MM = (a << SHIFT_A) | (b << SHIFT_B) | (T.sizeof << SHIFT_SIZE); } Usage is like: enum C1 = MM!(1, 2, A); enum C2 = MM!(3, 4, B);
Jul 07 2011
prev sibling next sibling parent teo <teo.ubuntu yahoo.com> writes:
On Thu, 07 Jul 2011 17:54:40 +0200, Trass3r wrote:

 The  TYPESIZE macro is used within another macro which defines
 constants. #define M(a,b,size) \
 	 ((a) << SHIFT_A) | \
 	 ((b)   << SHIFT_B) | \
 	 ((size) << SHIFT_SIZE))
 #define MM(a,b,type)	    M((a),(b),(TYPESIZE(type)))

 Example:
 #define C1    MM(1, 2, struct A)
 #define C2    MM(3, 4, struct B)

 How can I translate that to D?

You could just get rid of that extra macro and directly pass A.sizeof. Otherwise you need to use templates. Can't say more cause I can't imagine what the heck this code is used for.

ioctl types BTW: there is no ioctl module within phobos
Jul 07 2011
prev sibling next sibling parent teo <teo.ubuntu yahoo.com> writes:
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.
Jul 07 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Jul 2011 16:23:33 -0400, teo <teo.ubuntu 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
Jul 08 2011
prev sibling next sibling parent teo <teo.ubuntu yahoo.com> writes:
On Fri, 08 Jul 2011 09:54:40 -0400, Steven Schveighoffer wrote:

 On Thu, 07 Jul 2011 16:23:33 -0400, teo <teo.ubuntu 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?

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.

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. Here an example usage: uint _IOC(uint dir, uint type, uint nr, uint size) { return (dir << _IOC_DIRSHIFT) | (type << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT); } uint _IO(uint type, uint nr) { return _IOC(_IOC_NONE, type, nr, 0); } uint _IOWR(uint type, uint nr, uint size) { return _IOC(_IOC_READ | _IOC_WRITE, type, nr, size); } In another module define the constants: const C1 = _IO(1, 2); const C2 = _IOWR(2, 3, A.sizeof);
Jul 11 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 11 Jul 2011 09:21:53 -0400, teo <teo.ubuntu 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 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?

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.

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
Jul 11 2011
prev sibling parent teo <teo.ubuntu yahoo.com> writes:
 I think you may be confusing function templates with plain templates?

templates on page 281 in TDPL. That is an eponymous template. Thanks.
Jul 12 2011