type casting question

Discussion in 'C Programming' started by raj, Sep 9, 2003.

  1. raj

    raj Guest

    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);
    }
    raj, Sep 9, 2003
    #1
    1. Advertising

  2. raj

    David Rubin Guest

    raj wrote:
    >
    > 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

    --
    Andre, a simple peasant, had only one thing on his mind as he crept
    along the East wall: 'Andre, creep... Andre, creep... Andre, creep.'
    -- unknown
    David Rubin, Sep 9, 2003
    #2
    1. Advertising

  3. raj

    Richard Bos Guest

    (raj) wrote:

    > '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
    Richard Bos, Sep 9, 2003
    #3
  4. On Tue, 9 Sep 2003, raj wrote:
    >
    > 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
    Arthur J. O'Dwyer, Sep 9, 2003
    #4
  5. raj

    Kevin Easton Guest

    raj <> wrote:
    > 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.
    Kevin Easton, Sep 10, 2003
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. kevin
    Replies:
    11
    Views:
    5,785
    Andrew McDonagh
    Jan 8, 2005
  2. heyo
    Replies:
    3
    Views:
    887
    Dan Pop
    Apr 1, 2004
  3. pete
    Replies:
    4
    Views:
    784
    Dan Pop
    Apr 2, 2004
  4. Wally Barnes
    Replies:
    3
    Views:
    511
    Wally Barnes
    Nov 20, 2008
  5. Sosuke

    Up casting and down casting

    Sosuke, Dec 20, 2009, in forum: C++
    Replies:
    2
    Views:
    551
    James Kanze
    Dec 20, 2009
Loading...

Share This Page