type casting question

R

raj

Hi,

I am a beginner and need help with the following:

'ifr_data' is (char *)
'args'      is  unsigned long args[4]

((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

What does the above statement do.?
Why should we type cast args again it is already of type 'unsigned
long.'
Why do we need to pass the address of ifr_data and later dereference,
if
I understood corrctly, using [].

Cant we do something like:
(unsigned long *) ifr.ifr_data = args



COMPLETE CODE: (remember 'ifr.ifr_data' is char *)
---------------
int br_device_ioctl32(struct bridge *br, unsigned long arg0, unsigned
long arg1, unsigned long arg2, unsigned long arg3)
{
unsigned long args[4];
        struct ifreq ifr;

        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        args[3] = arg3;

        memcpy(ifr.ifr_name, br->ifname, IFNAMSIZ);
        ((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

        return ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
}
 
D

David Rubin

raj said:
Hi,

I am a beginner and need help with the following:

'ifr_data' is (char *)
'args' is unsigned long args[4]

((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

What does the above statement do.?

This produces undefined behavior because ifr_data is not guaranteed to
be properly aligned to a ulong type. What you probably want to do is
write a small function or macro which puts the correct bytes in ifr_data
by shifting and masking args.

/david
 
R

Richard Bos

'ifr_data' is (char *)
'args'      is  unsigned long args[4]

((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

What does the above statement do.?

Bugger all useful. It casts the address of args to an unsigned long,
then assigns the unsigned-long-was-address to the memory officially
occupied by the char * called ifr_data . The way this is done is not
guaranteed to work (think bus errors), and where it does, is not
guaranteed to result in useful values.
Why should we type cast args again it is already of type 'unsigned
long.'

args is not of type unsigned long. It's an array.
Why do we need to pass the address of ifr_data and later dereference,
if I understood corrctly, using [].

You're not passing anything. You're casting the address of ifr_data to a
type it does not really have: ifr.ifrdata is treated as if _it_ is an
unsigned long, which is, clearly, wrong.
As for the [0], you don't _really_ need them, you can also use a *. In
fact, that's probably slightly(!) clearer:
*((unsigned long *)(&ifr.ifr_data)) = (unsigned long)args;
Cant we do something like:
(unsigned long *) ifr.ifr_data = args

No. For one thing, you cannot assign to a cast expression, because a
cast delivers a simple value, not an lvalue.
COMPLETE CODE: (remember 'ifr.ifr_data' is char *)
---------------
int br_device_ioctl32(struct bridge *br, unsigned long arg0, unsigned
long arg1, unsigned long arg2, unsigned long arg3)
{
unsigned long args[4];
        struct ifreq ifr;

        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        args[3] = arg3;

        memcpy(ifr.ifr_name, br->ifname, IFNAMSIZ);
        ((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

        return ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
}

This is system-specific code. I suspect the secret to that odd
assignment lies in what ioctl() expects in its third parameter. I also
suspect that this was written for a system that does, in fact, make the
guarantees I told you above C itself does not make. Finally, I suspect
this code was not exactly meant for beginners, and suggest you don't
worry if you don't understand it yet.

Richard
 
A

Arthur J. O'Dwyer

I am a beginner and need help with the following:

'ifr_data' is (char *)
'args'      is  unsigned long args[4]

((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

What does the above statement do.?

Assigns 'args' to 'ifr.ifr_data', but in a roundabout way that
introduces undefined behavior. *However*, on systems where this
sort of thing does "work," it probably won't change the bit
representation of 'args' during the assignment.

Standard C (no undefined behavior):

ifr.ifr_data = (char *) args;

Standard C (maybe closer to intended effect; has UB):

char *temp = args;
memcpy(&ifr.ifr_data, temp, sizeof temp);

Why should we type cast args again it is already of type 'unsigned
long.'

'args' is *not* of type 'unsigned long'. You told us it was of
type 'unsigned long [4]'; which, in this context, decays to a
pointer to the first element in the array -- that is, to a pointer
to unsigned long ('unsigned long *'). That's not the same thing
as 'unsigned long'.
Why do we need to pass the address of ifr_data and later dereference,
if I understood corrctly, using [].

You don't "pass" the address of 'ifr.ifr_data' anywhere. You "compute"
it. And see below.
Cant we do something like:
(unsigned long *) ifr.ifr_data = args

No. Try that on a conforming compiler, and read the error message
you get.
The '(unsigned long *)' tells the compiler to calculate the value
gotten by treating 'ifr.ifr_data' as an unsigned long. For example,
that value might be 0x55D06A32. Then you're asking the compiler to
assign something to that value. *That doesn't make any sense!*
You can't assign to a cast-expression any more than you can assign
to an addition-expression like '1+1'.

<snip code>

I recommend you try the first alternative method I proposed, and
see whether it works. (But if this is a serious project, be extra-
careful to document the change, and make sure you can tell whether
it's working or not! Just because X compiles doesn't mean X will
work.)

HTH,
-Arthur
 
K

Kevin Easton

raj said:
Hi,

I am a beginner and need help with the following:

'ifr_data' is (char *)
'args' is unsigned long args[4]

((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args;

What does the above statement do.?

The above statement is nonsense. It tries to access a "char *" object
as if it were an "unsigned long", and it casts an (unsigned long *) to
(unsigned long).

The correct way to do what it appears to be *trying* to do is much
simpler:

ifr.ifr_data = (char *)args;
Why should we type cast args again it is already of type 'unsigned
long.'

No it isn't - args is of type ``unsigned long [4]''. In an expression
where it's not the operand of either the unary-& or sizeof operators,
it is evaluated as a pointer to the first element of the array, and the
resulting value has type ``unsigned long *''.
Why do we need to pass the address of ifr_data and later dereference,
if I understood corrctly, using [].

Because it wants to pretend to the compiler that ifr_data is an unsigned
long (which is a silly thing to do anyway).
Cant we do something like:
(unsigned long *) ifr.ifr_data = args

No, the result of a cast operator is not an lvalue, so it can't be
assigned to. That's just as nonsensical as writing:

a + 2 = 10;

- Kevin.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top