?

Log in

No account? Create an account

fanf

Pointer magic

« previous entry | next entry »
20th Nov 2007 | 21:42

The following C type definition can be used for declaring local and global structure objects. You can initialize them as if they were bare structures, because C doesn't mind if you omit curly brackets in initializers (though gcc -Wall will complain). You can also use the typedef to declare function arguments, in which case the function will expect a pointer to the structure instead of a copy of it. Furthermore, when you use a variable declared with this typedef, it will be quietly converted into a pointer to the structure just as is expected by the function. This avoids a load of & operators and gives you a sort of poor-man's C++ pass-by-reference.

        typedef struct mytype {
                /* member declarations */
        } mytype[1];

        mytype var;

        int func(mytype arg);

        func(var);

ETA: it seems this trick is used by GMP (see the last paragraph of that page)

Poll #1092168 Pointer magic

This idea is

wonderful
1(5.3%)
cunning
2(10.5%)
obfuscated
2(10.5%)
disgusting
0(0.0%)
criminal
0(0.0%)
My parent process died by crashing into an array of structures, you insensitive clot.
0(0.0%)

| Leave a comment | Share

Comments {15}

Simon Tatham

from: simont
date: 20th Nov 2007 22:35 (UTC)

This is the same trick used by jmp_buf, isn't it? Hence why you don't have to specify the & when passing a jmp_buf to a function which is obviously going to modify it (such as setjmp).

Reply | Thread

Tony Finch

from: fanf
date: 20th Nov 2007 23:00 (UTC)

So it is :-) Though it seems older unices just used an array of ints.

Reply | Parent | Thread

ewx

from: ewx
date: 20th Nov 2007 22:49 (UTC)

I use it often and like it because I can always use -> and leave out the & regardless of whether I'm in the function that declared the auto object or one that has been passed a pointer to it; as well as not having to care where I am when writing, it means search/search and replace is simplified. An interesting example of typing more characters in an essentially mechanical way nonetheless reducing the total amount of work.

Reply | Thread

(Deleted comment)
(Deleted comment)

Peter Maydell

from: pm215
date: 21st Nov 2007 05:20 (UTC)

I don't like this for the same reason I don't like C++'s pass-by-reference -- it hides the distinction between passing a thing and passing a pointer to a thing, which IMHO is a fundamental difference that you really want to know about.

Reply | Thread

Simon Tatham

from: simont
date: 21st Nov 2007 09:09 (UTC)

I agree with this.

Also if you want to define a more complex type with one of these things as its base type, it's hard to work out how. When I was working with GMP a while back I occasionally wanted to write a function which took a pointer to an array of mpf_t; I managed it in the end by just adding or removing *s until the compiler stopped complaining, but I wouldn't say I understand the syntactic rules which make the right answer right and the wrong ones wrong. (And, just to put that in perspective, I do feel that I understand pretty much all the rest of the C declarator syntax, which I know isn't a statement all C programmers could make!)

Reply | Parent | Thread

gareth_rees

from: gareth_rees
date: 21st Nov 2007 10:19 (UTC)

If in doubt, I suggest using something like this:
typedef mpf_t array_of_unknown_size_of_mpf_t[];
typedef array_of_unknown_size_of_mpf_t *pointer_to_array_of_unknown_size_of_mpf_t;

Reply | Parent | Thread

Andrew

from: nonameyet
date: 21st Nov 2007 09:01 (UTC)

Hmm. My C appears to be too rusty to get the full subtlety of this but I think I agree with pm215 that in C you need to know whether you have a thing or a pointer to a thing. Unless you can use this consistently and everywhere, so that you never need to remember which, it is probably more dangerous to forget that you need to remember.

IIRC K&R C didn't allow you to pass arrays, so I'd be very uncomfortable about using this on a pre-ANSI C compiler.
(That isn't likely these days, so that is really an aesthetic complaint.)

Reply | Thread

ewx

from: ewx
date: 21st Nov 2007 12:04 (UTC)

I think you've confused it with the old struct passing behavior; AFAIK the array-to-pointer decay has always been that way.

Reply | Parent | Thread

ewx

from: ewx
date: 21st Nov 2007 12:05 (UTC)

Oh, and all sorts of standard modern things don't work on pre-ANSI implementations: const and prototypes for instance. So suggesting that as even just an aesthetic reason is frankly rather silly.

Reply | Parent | Thread

Peter Maydell

from: pm215
date: 21st Nov 2007 13:17 (UTC)

Yeah, even gcc requires an ANSI C89 compiler these days. K&R non-prototyped function syntax is almost as dead as the "var =+ 4;" autoincrement syntax. (Aside: I wonder if the Green Hills C compiler still has the option switch to support =+ ...)

Reply | Parent | Thread

Andrew

from: nonameyet
date: 21st Nov 2007 14:09 (UTC)

I was indeed thinking of that.

Reply | Parent | Thread

Gerald the cuddly duck

from: gerald_duck
date: 21st Nov 2007 10:54 (UTC)

I don't like some of the darker corners of C's array behaviour anyway, and this exhibits them in a place where you're not expecting them. Particularly, while func(var) passes by reference, mytype another = var; makes a copy. C++'s references have their faults, but argument binding behaviour differing from assignment behaviour isn't one of them.

Reply | Thread

from: drj11
date: 4th Jan 2008 09:32 (UTC)

mytype another = var isn't valid C, so it doesn't make a copy.

I've seen this trick used for va_list so that you could pass vararg lists to subroutines and have it work correctly, though the general form of this is not required by the standard.

I wouldn't really consider this a dark corner of C's array behaviour, it's simply one of those things you have to know before calling yourself a C programmer.

Reply | Parent | Thread