[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Puzzling #define

Edward Rutherford

6/2/2011 9:41:00 PM

I'm having trouble grasping the meaning behind the following:

#define MAKE(z, w) (int)(&(((z *)0)->w))

Can anyone fill me in?

Specifically, I'm confused on the ((z *)0) part. I'm not exactly sure
what that would give me.

T. I. A.
12 Answers

christian.bau

6/2/2011 9:46:00 PM

0

On Jun 2, 10:41 pm, Edward Rutherford
<edward.p.rutherfor...@REMOVETHIS.gmail.com> wrote:
> I'm having trouble grasping the meaning behind the following:
>
> #define MAKE(z, w) (int)(&(((z *)0)->w))
>
> Can anyone fill me in?
>
> Specifically, I'm confused on the ((z *)0) part.  I'm not exactly sure
> what that would give me.

Looks like a horrible attempt to create a macro that does the same
thing as offsetof, except that this one invokes undefined behaviour.

Assuming that the parameter z in the macro is some type, most likely a
struct type, (z *)0 takes the number 0, and converts it to a pointer
to an object of type z. In other words, a null pointer of type z*.

falk

6/2/2011 10:10:00 PM

0

In article <53dbaa2b-5fe0-4ce3-9696-7b812787d389@u19g2000vbi.googlegroups.com>,
christian.bau <christian.bau@cbau.wanadoo.co.uk> wrote:
>On Jun 2, 10:41 pm, Edward Rutherford
><edward.p.rutherfor...@REMOVETHIS.gmail.com> wrote:
>> I'm having trouble grasping the meaning behind the following:
>>
>> #define MAKE(z, w) (int)(&(((z *)0)->w))
>>
>> Can anyone fill me in?
>>
>> Specifically, I'm confused on the ((z *)0) part.  I'm not exactly sure
>> what that would give me.

Taken as a whole, the macro returns the byte offset of element 'w'
within an object of type 'z'. Why they chose to name it MAKE is
a mystery to me.

Expanding: ((z *)0) is zero, cast as a pointer to z. &(((z *)0)->w)
is the address of element 'w' within a 'z' object. Because this
particular 'z' object starts at zero, this pointer is also the
byte address of 'w'. The (int) cast causes the whole macro to return
an integer value of the byte address.

This macro makes some assumptions about the underlying CPU architecture.
If you look up offsetof() in Wikipedia, you'll find a somewhat more
portable definition of offsetof() along with a discussion about
the undefined behavior that christian.bau mentioned.

--
-Ed Falk, falk@despams.r.us.com
http://thespamdiaries.blo...

Joel C. Salomon

6/2/2011 10:22:00 PM

0

On 06/02/2011 05:41 PM, Edward Rutherford wrote:
> I'm having trouble grasping the meaning behind the following:
>
> #define MAKE(z, w) (int)(&(((z *)0)->w))
>
> Can anyone fill me in?
>
> Specifically, I'm confused on the ((z *)0) part. I'm not exactly sure
> what that would give me.

The expression `(z *)0` is a null pointer of type `z*`. This isn't
quite the same as a "zero-valued" pointer (e.g., a null pointer may have
some arbitrary implementation-specific bit pattern that serves as a
trap), but the writer makes the assumption that null = zero.

Assuming for the moment that `(z *)0` gives you a zero-valued pointer,
the expression `((z *)0)->w` pretends there is a structure of type `z`
at address 0, and accesses the `w` field of the structure. The address
of this field is then taken, and the resulting address is cast to `int`.

E.g., given the structure definition
struct foo{
int32_t bar;
int32_t bas;
};
and plausible assumptions about structure layout and byte size,
`MAKE(foo foo, bas)` is intended to yield 4.

(Oh, and if differently-typed pointers have different representations on
your system, this will break horribly in very interesting ways.)

See also the `offsetof()` macro in <stddef.h>, which accomplishes this
same thing, but is defined by your compiler provider in a way which is
guaranteed to work on your machine.


By the way: Is there a portable way to get a zero-valued pointer? To
take a concrete example, assume a system where uintptr_t is defined, and
on which
union intptr {
void *p;
uintptr_t i;
};
/* ... */
union intptr u = {.p = 0};
assert(u.i == 0xDEADBEEF);
holds. On this system, is there an initializer for a pointer value for
which
union intptr v = {.p = ZERO_PTR};
assert(u.i == 0);
holds?

This should work:
#define ZERO_PTR ((intptr){.i = 0}).p
but is there a way to not require the union definition?

I'm wondering if `(void *)((uintptr_t)0)` might do the trick -- or is
the void* <-> uintptr_t conversion defined to map null to zero?

--Joel

Shao Miller

6/3/2011 12:34:00 AM

0

On 6/2/2011 5:09 PM, Edward A. Falk wrote:
> This macro makes some assumptions about the underlying CPU architecture.
> If you look up offsetof() in Wikipedia, you'll find a somewhat more
> portable definition of offsetof() along with a discussion about
> the undefined behavior that christian.bau mentioned.
>

Speaking of which, in:

#define fun_offsetof(type, member) \
(sizeof (char[(char *)&((type *)0)->member - (char *)0]))

struct s {
int x;
short y;
int z;
};

int main(void) {
return (int)fun_offsetof(struct s, z);
}

I wonder if that's any more portable...

Shao Miller

6/3/2011 12:47:00 AM

0

On 6/2/2011 5:21 PM, Joel C. Salomon wrote:
> On 06/02/2011 05:41 PM, Edward Rutherford wrote:
>> I'm having trouble grasping the meaning behind the following:
>>
>> #define MAKE(z, w) (int)(&(((z *)0)->w))
>>
> Assuming for the moment that `(z *)0` gives you a zero-valued pointer,
> the expression `((z *)0)->w` pretends there is a structure of type `z`
> at address 0, and accesses the `w` field of the structure. The address
> of this field is then taken, and the resulting address is cast to `int`.
>

Are you sure about "accesses the `w` field"? 6.3.2.1p2 suggests to me
that there is no access[3.1p1].

Joel C. Salomon

6/3/2011 12:49:00 AM

0

On 06/02/2011 08:47 PM, Shao Miller wrote:
> On 6/2/2011 5:21 PM, Joel C. Salomon wrote:
>> Assuming for the moment that `(z *)0` gives you a zero-valued pointer,
>> the expression `((z *)0)->w` pretends there is a structure of type `z`
>> at address 0, and accesses the `w` field of the structure.
>
> Are you sure about "accesses the `w` field"? 6.3.2.1p2 suggests to me
> that there is no access[3.1p1].

You're right, of course; an *actual* access would be a Bad Thing. I was
using the word "access" somewhat loosely. (Also, if I read this right,
offsetof() is supposed to work at compile-time.)

Good catch.

--Joel

Tim Rentsch

6/3/2011 1:39:00 AM

0

"Joel C. Salomon" <joelcsalomon@gmail.com> writes:

[snip]
>
> By the way: Is there a portable way to get a zero-valued pointer? To
> take a concrete example, assume a system where uintptr_t is defined, and
> on which
> union intptr {
> void *p;
> uintptr_t i;
> };
> /* ... */
> union intptr u = {.p = 0};
> assert(u.i == 0xDEADBEEF);
> holds. On this system, is there an initializer for a pointer value for
> which
> union intptr v = {.p = ZERO_PTR};
> assert(u.i == 0);
> holds?
>
> This should work:
> #define ZERO_PTR ((intptr){.i = 0}).p
> but is there a way to not require the union definition?

How about this:

#define ZERO_POINTER ALL_ZEROES( void * )

#define ALL_ZEROES(T) \
( ( (union { unsigned char uc[sizeof(T)]; T it; }){{0}} ).it )

Morris Keesan

6/3/2011 2:34:00 AM

0

On Thu, 02 Jun 2011 18:21:36 -0400, Joel C. Salomon
<joelcsalomon@gmail.com> wrote:

> By the way: Is there a portable way to get a zero-valued pointer?

Assuming that by "zero-valued pointer", you mean a pointer all of whose
bits are zero,

#include <string.h>
void *zerop;
memset(&zerop, 0, sizeof zerop);

causes zerop to be a "zero-valued" (void *). I don't think you can
portably do anything with it, because it could then contain a trap
representation. Even using it as an initializer for other pointers
could be a problem.
--
Morris Keesan -- mkeesan@post.harvard.edu

Shao Miller

6/3/2011 2:56:00 AM

0

On 6/2/2011 8:39 PM, Tim Rentsch wrote:
> "Joel C. Salomon"<joelcsalomon@gmail.com> writes:
>
> [snip]
>>
>> By the way: Is there a portable way to get a zero-valued pointer? To
>> take a concrete example, assume a system where uintptr_t is defined, and
>> on which
>> union intptr {
>> void *p;
>> uintptr_t i;
>> };
>> /* ... */
>> union intptr u = {.p = 0};
>> assert(u.i == 0xDEADBEEF);
>> holds. On this system, is there an initializer for a pointer value for
>> which
>> union intptr v = {.p = ZERO_PTR};
>> assert(u.i == 0);
>> holds?
>>
>> This should work:
>> #define ZERO_PTR ((intptr){.i = 0}).p
>> but is there a way to not require the union definition?
>
> How about this:
>
> #define ZERO_POINTER ALL_ZEROES( void * )
>
> #define ALL_ZEROES(T) \
> ( ( (union { unsigned char uc[sizeof(T)]; T it; }){{0}} ).it )
>

Agreed. :) I use that pattern, too, in C99.

Shao Miller

6/3/2011 3:37:00 AM

0

On 6/2/2011 7:33 PM, Shao Miller wrote:
> On 6/2/2011 5:09 PM, Edward A. Falk wrote:
>> This macro makes some assumptions about the underlying CPU architecture.
>> If you look up offsetof() in Wikipedia, you'll find a somewhat more
>> portable definition of offsetof() along with a discussion about
>> the undefined behavior that christian.bau mentioned.
>>
>
> Speaking of which, in:
>
> #define fun_offsetof(type, member) \
> (sizeof (char[(char *)&((type *)0)->member - (char *)0]))
>
> struct s {
> int x;
> short y;
> int z;
> };
>
> int main(void) {
> return (int)fun_offsetof(struct s, z);
> }
>
> I wonder if that's any more portable...

Or perhaps the more ludicrous:

#define DUMMY_FUNC(type) \
((type * (*)(void))main)

#define NULLOF(type) (1 ? 0 : DUMMY_FUNC(type)())

#define fun_offsetof(type, member) \
(sizeof (char[ \
(char *)&(NULLOF(type)->member) - \
(char *)NULLOF(type) \
]))

struct s {
int x;
short y;
int z;
};

int main(void) {
return (int)fun_offsetof(struct s, z);
}

The "hope" being (for both examples) that 'sizeof' "helps" to avoid
evaluating the '->' operator's expression when its left operand is a
null pointer. The silly example above produces a null pointer without a
cast (for what that's worth, heh) and the ternary conditional operator
prevents 'main' from ever being called as the wrong function type. Just
for fun.