By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,233 Members | 1,790 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,233 IT Pros & Developers. It's quick & easy.

T val = ({ semicolon_separated_statements });

P: n/a
Hello,

I have the following code that I wrote expanding and merging a couple
of macros from the Linux kernel and that I've integrated in a complete
C++ program so that it can be compiled as it is.

It is now irrelevant why someone would write some code like that,
however it is needed by the linked lists API in that kernel and I need
something like that in order to write a library to handle "linked lists
of multilists objects"

The central part of this program wants to get a pointer to an object
instantiated with a struct, knowing only (1) the address of an element
of the same object, (2) the name of that same element and (3) the type
of the struct in which that element is contained.

#include <iostream>

struct list_head {
struct list_head *prev, *next;
};

int main()
{
struct mine {
long ll;
int ii;
char cc;
struct list_head mm;
} *ps;

ps = new struct mine;
ps->ll = 99;
ps->ii = 1;
ps->cc = 'k';
ps->mm.prev = 0;
ps->mm.next = 0;
struct list_head *pmm = &ps->mm;

// I want *ptr to obtain the address of the single object
instantiated
// from the struct, forgetting I have *ps because I won't have it
// in the real code. Now I have (1) a pointer to an element of the
// object (*pmm),(2) the name of the same element (mm), (3) the
// type and the name of the 'container' of that same element
(struct mine).

struct mine *ptr = ({
const typeof( ((struct mine *)0)->mm ) *__mptr = (pmm);
(struct mine *)( (char *)__mptr - ( (size_t) &((struct mine
*)0)->mm ) );
});

/* Alternative method

struct mine *ptr = ({
const typeof( ((typeof(*ptr)*)0)->mm ) *__mptr = (pmm);
(typeof(*ptr)*)( (char *)__mptr - ( (size_t)
&((typeof(*ptr)*)0)->mm ) );
});
*/

std::cout << ptr->ll << ", " << ptr->ii << ", " << ptr->cc << '\n';

delete ps;
return 0;
}

As you can see, there an g++ extension (typeof) is used to get the type
of the object: typeof(*ptr) should return "struct mine". We'll talk
about it in a moment.

Questions:

1) The first and most important (to me) question is about the
construction of the assignement of "ptr". Here I have:

T *ptr = ({ semicolon_separated_statements });

What kind of construct is it? Is it another g++ extension or it is a
legal C++ standard statement? If you compile the program you would
notice that parenthesis can't be deleted, because you would get error
messages from the compiler.If it is not standard how would you change
the whole assignement construction?

2) I suppose that "((struct mine *)0)" is a pointer to the first
element of the struct mine object and "((struct mine *)0)->mm" is the
element "mm". I've never met this construction before, but now I notice
that it is often used in Linux. Is it another g++ extension? If yes how
would you substitute it in order to conform to the standard?

3) Has the standard anything similar to the word "typeof"? Which can I
substitute it with?

4) My last question is about the possibility to write a more cleaner
and standard function that returns the address of the either a class or
a struct objects provided only the same three informations (as
arguments) that you see in the program.

As usually I am sorry for my poor English and I hope I was able to
correctly explain my questions.

Thanks in advance to all of you who will reply.

Ciao,

fabio de francesco

Jul 23 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a
Fabio De Francesco wrote:
Hello,

I have the following code that I wrote expanding and merging a couple
of macros from the Linux kernel and that I've integrated in a complete
C++ program so that it can be compiled as it is.


The Linux kernel is written in GNU C, i.e. C with GNU extensions. It is
not intended to be compiled with anything other than gcc (and different
kernels require -- or, in some cases, prefer -- specific versions).

Kernel code both takes advantage of GCC extensions and knowledge about
the GCC implementation that's outside of the standard (either C or C++).

See: http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

HTH,
--ag

BTW - your English is fine. ;-)

--
Artie Gold -- Austin, Texas
http://it-matters.blogspot.com (new post 12/5)
http://www.cafepress.com/goldsays
Jul 23 '05 #2

P: n/a
Fabio De Francesco wrote:

The central part of this program wants to get a pointer to an object
instantiated with a struct, knowing only (1) the address of an element of the same object, (2) the name of that same element and (3) the type of the struct in which that element is contained.

struct mine *ptr = ({
const typeof( ((struct mine *)0)->mm ) *__mptr = (pmm);
(struct mine *)( (char *)__mptr - ( (size_t) &((struct mine
*)0)->mm ) );
});
You could achieve the same thing in a standard way:

mine *ptr = (mine *)((char *)(pmm) - offsetof(mine, mm));

The standard macro offsetof(A,B) gives the offset (in bytes)
of a member named B in the structure A. This only works for
POD structures (ie. ones that are also structures in C).
'pmm' is cast to (char *) so that when you subtract from it,
you are subtracting byte-sized elements.

This would potentially give undefined behaviour (due to
alignment issues) if pmm didn't actually point to a mine.

Note that 'struct' is superfluous in this context, in C++.

Tthe original construction of '__mptr' is entirely
redundant, because it is merely 'pmm' cast to the same type.
It might be useful if this were a macro expansion, and pmm
occurred twice in the result, but it doesn't. (Unless you
didn't paste your exact code).
Questions:

1) The first and most important (to me) question is about the
construction of the assignement of "ptr". Here I have:

T *ptr = ({ semicolon_separated_statements });

What kind of construct is it?
http://gcc.gnu.org/onlinedocs/gcc-2....c_4.html#SEC62

foo = ({ int bar = 0; bar + 1; })
means
int bar = 0;
foo = bar+1;
except that 'bar' goes out of scope after the expression 'bar+1'.
So you could re-write your original example without that construct
(unless you have some pressing need for it to all be one expression).
2) I suppose that "((struct mine *)0)" is a pointer to the first
element of the struct mine object
Actually it is a null pointer, of type 'mine *'. Casting 0 to a
pointer type always gives a null pointer.
and "((struct mine *)0)->mm" is the element "mm".
I've never met this construction before, but now I notice that
it is often used in Linux. Is it another g++ extension? If yes how
would you substitute it in order to conform to the standard?
It works on some systems where the null pointer is at address 0,
and the system doesn't object to you dereferencing null.
To conform to the standard, use offsetof(). (On those systems,
offsetof() is usually implemented in this way).
3) Has the standard anything similar to the word "typeof"? Which can I substitute it with?


No. But if I understood you correctly, it isn't needed for
this example, as you have access to the name of 'struct mine' already.

Jul 23 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.