Noob Q: How to properly type cast in this case

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • * Tong *

    Noob Q: How to properly type cast in this case

    Hi,

    I couldn't figure out how to properly type cast in this case:

    $ cat -n type_cast.c
    1 #include <stdio.h>
    2
    3 typedef unsigned char Byte;
    4 typedef signed char Small_Int;
    5
    6 typedef struct _list
    7 {
    8 struct _list *np; /* Pointer to next */
    9 struct _list *lp; /* Pointer to last */
    10 Byte type;
    11 union {
    12 void *dp; /* Pointer to data */
    13
    14 /* These fields used for a small amount of data */
    15 struct {
    16 Byte d1;
    17 Byte d2;
    18 Byte d3;
    19 Byte d4;
    20 } bytes;
    21
    22 }data;
    23
    24 } List;
    25
    26 List *markedplace;
    27 Small_Int i;
    28
    29 main(int argc,char * argv[])
    30 {
    31 i = 2;
    32 markedplace->data.dp = NULL;
    33 (Small_Int *)markedplace->data.dp = i;
    34 }

    $ gcc type_cast.c
    type_cast.c: In function 'main':
    type_cast.c:33: error: lvalue required as left operand of assignment

    How should I fix it?

    Thanks


    --
    Tong (remove underscore(s) to reply)


  • Joachim Schmitz

    #2
    Re: Noob Q: How to properly type cast in this case

    * Tong * wrote:
    Hi,
    >
    I couldn't figure out how to properly type cast in this case:
    Why cast at all?
    >
    $ cat -n type_cast.c
    1 #include <stdio.h>
    2
    3 typedef unsigned char Byte;
    4 typedef signed char Small_Int;
    5
    6 typedef struct _list
    7 {
    8 struct _list *np; /* Pointer to next */
    9 struct _list *lp; /* Pointer to last */
    10 Byte type;
    11 union {
    12 void *dp; /* Pointer to data */
    13
    14 /* These fields used for a small amount of data */
    15 struct {
    16 Byte d1;
    17 Byte d2;
    18 Byte d3;
    19 Byte d4;
    20 } bytes;
    21
    22 }data;
    23
    24 } List;
    25
    26 List *markedplace;
    27 Small_Int i;
    28
    29 main(int argc,char * argv[])
    30 {
    31 i = 2;
    32 markedplace->data.dp = NULL;
    33 (Small_Int *)markedplace->data.dp = i;
    markedplace->data.dg=&i;
    Is probably what you should do.
    34 }
    >
    $ gcc type_cast.c
    type_cast.c: In function 'main':
    type_cast.c:33: error: lvalue required as left operand of assignment
    >
    How should I fix it?
    Don't cast an lvalue. Avoid casts wherever possible.
    Here use the address of i to set the value of dp, which is a (void) pointer.
    Thanks
    Bye, Jojo


    Comment

    • Joachim Schmitz

      #3
      Re: Noob Q: How to properly type cast in this case

      Joachim Schmitz wrote:
      * Tong * wrote:
      <snip>
      > 33 (Small_Int *)markedplace->data.dp = i;
      markedplace->data.dg=&i;
      Modulo typos...
      markedplace->data.dp=&i;

      I was concentrating to not write marketplace instead 8-)
      Is probably what you should do.

      Comment

      • Andrew Kerr

        #4
        Re: Noob Q: How to properly type cast in this case

        Joachim Schmitz wrote:
        Joachim Schmitz wrote:
        >* Tong * wrote:
        <snip>
        >> 33 (Small_Int *)markedplace->data.dp = i;
        >markedplace->data.dg=&i;
        Modulo typos...
        markedplace->data.dp=&i;
        If the original poster were trying to store the address of i in data.dp,
        then the parents of this reply are correct. As they have stated, you
        should write:

        markedplace->data.dp = &i;

        If however you are trying to store the value of i into one of bytes::d1,
        ::d2, ::d3, or ::d4, you should use the following:

        markedplace->data.bytes.d 1 = (Small_Int)i; // or {d2, d3, d4}

        That said, this is a very unusual thing to want to do.

        --
        Andrew Kerr

        Comment

        • * Tong *

          #5
          Re: Noob Q: How to properly type cast in this case

          Thanks for the reply Joachim and Andrew.

          Sorry, I noticed that I've screwed my example, let me try again.

          On Thu, 29 May 2008 16:41:47 +0200, Joachim Schmitz wrote:
          >I couldn't figure out how to properly type cast in this case:
          Why cast at all?
          I am trying to compile a big program, in which the following line gives me
          the "lvalue required" error:

          (Small_Int *)markedplace->data.dp = p;

          The following is what I stripped out for the illustration purpose:

          $ cat -n type_cast.c
          1 #include <stdio.h>
          2
          3 typedef unsigned char Byte;
          4 typedef signed char Small_Int;
          5
          6 typedef struct _list
          7 {
          8 struct _list *np; /* Pointer to next */
          9 struct _list *lp; /* Pointer to last */
          10 Byte type;
          11 union {
          12 void *dp; /* Pointer to data */
          13
          14 /* These fields used for a small amount of data */
          15 struct {
          16 Byte d1;
          17 Byte d2;
          18 Byte d3;
          19 Byte d4;
          20 } bytes;
          21
          22 }data;
          23
          24 } List;
          25
          26 List *markedplace;
          27 Small_Int i;
          28
          29 main(int argc,char * argv[])
          30 {
          31 markedplace->data.dp = NULL;
          32 markedplace->data.dp = &i;
          33 (Small_Int *)markedplace->data.dp = &i;
          34 }

          $ gcc type_cast.c
          type_cast.c: In function 'main':
          type_cast.c:33: error: lvalue required as left operand of assignment

          So we don't need to type cast for void pointers? Line 32 was actually how I
          fixed it, but I want to know how to properly type cast if I have to.

          Thanks

          --
          Tong (remove underscore(s) to reply)


          Comment

          • Jens Thoms Toerring

            #6
            Re: Noob Q: How to properly type cast in this case

            * Tong * <sun_tong_001@u sers.sourceforg e.netwrote:
            I am trying to compile a big program, in which the following line gives me
            the "lvalue required" error:
            (Small_Int *)markedplace->data.dp = p;
            The following is what I stripped out for the illustration purpose:
            $ cat -n type_cast.c
            1 #include <stdio.h>
            2
            3 typedef unsigned char Byte;
            4 typedef signed char Small_Int;
            5
            6 typedef struct _list
            7 {
            8 struct _list *np; /* Pointer to next */
            9 struct _list *lp; /* Pointer to last */
            10 Byte type;
            11 union {
            12 void *dp; /* Pointer to data */
            13
            14 /* These fields used for a small amount of data */
            15 struct {
            16 Byte d1;
            17 Byte d2;
            18 Byte d3;
            19 Byte d4;
            20 } bytes;
            21
            22 }data;
            23
            24 } List;
            25
            26 List *markedplace;
            27 Small_Int i;
            28
            29 main(int argc,char * argv[])
            30 {
            31 markedplace->data.dp = NULL;
            32 markedplace->data.dp = &i;
            33 (Small_Int *)markedplace->data.dp = &i;
            34 }
            $ gcc type_cast.c
            type_cast.c: In function 'main':
            type_cast.c:33: error: lvalue required as left operand of assignment
            So we don't need to type cast for void pointers?
            Every pointer to a object (but not functions) can be converted
            to a void pointer and back again without problems (and even
            without an explicit cast). The assignment

            markedplace->data.dp = &i;

            implicitely converts the value of the right side (which is a pointer
            to a 'Small_Int') to a void pointer as if you had written explicitely

            markedplace->data.dp = ( void * ) &i;

            But you can't cast the left hand side. It stays a void pointer
            whatever you do. If it would work otherwise why shouldn't also
            e.g.

            int x = 13;

            ( double ) x = 3.1419265359;

            work in changing 'x', so it suddenly has a type of double?

            Actually, the cast on the left hand side takes the value
            stored in 'x' and converts that value to a double. And after
            this operation the compiler suddenly sees

            13.0 = 3.1419265359;

            and complains rightly about "lvalue required as left operand
            of assignment" since now you have something on the left hand
            side that isn't something a value could be assigned to since
            it's already a value.
            Line 32 was actually how I
            fixed it, but I want to know how to properly type cast if I have to.
            By only casting values, not trying to "cast" objects. If you
            do e.g.

            int x;
            double pi = 3.1419265359;

            x = ( int ) pi;

            you don't cast the variable 'pi', you only cast the value that
            is stored in the 'pi'. So it's a valid cast since it doesn't try
            to change anything about the type of 'pi'. And if you do e.g.

            int i;
            void *v = &i;

            * ( int * ) v = 42;

            then again you cast the value stored in 'v' (not 'v' itself) to
            an int pointer and then write 42 to that address. As you see, a
            cast can also appear on the left hand side, but only if a value
            is acceptable at that place on the left hand side.

            Regards, Jens
            --
            \ Jens Thoms Toerring ___ jt@toerring.de
            \______________ ____________ http://toerring.de

            Comment

            • Ensemble

              #7
              Re: Noob Q: How to properly type cast in this case

              Thanks a lot for the step by step and comprehensive explanation.

              On Thu, 29 May 2008 20:36:08 +0000, Jens Thoms Toerring wrote:
              . . .
              int i;
              void *v = &i;
              >
              * ( int * ) v = 42;
              . . .

              Comment

              • Barry Schwarz

                #8
                Re: Noob Q: How to properly type cast in this case

                On Thu, 29 May 2008 09:33:31 -0500, * Tong *
                <sun_tong_001@u sers.sourceforg e.netwrote:
                >Hi,
                >
                >I couldn't figure out how to properly type cast in this case:
                There is no such thing as type cast in C. There is only cast.
                Furthermore, you cannot cast objects, only values.
                >
                >$ cat -n type_cast.c
                1 #include <stdio.h>
                By including these line numbers, you have made it annoyingly difficult
                for anyone to compile your code.
                2
                3 typedef unsigned char Byte;
                4 typedef signed char Small_Int;
                5
                6 typedef struct _list
                7 {
                8 struct _list *np; /* Pointer to next */
                9 struct _list *lp; /* Pointer to last */
                10 Byte type;
                11 union {
                12 void *dp; /* Pointer to data */
                13
                14 /* These fields used for a small amount of data */
                15 struct {
                16 Byte d1;
                17 Byte d2;
                18 Byte d3;
                19 Byte d4;
                20 } bytes;
                21
                22 }data;
                23
                24 } List;
                25
                26 List *markedplace;
                markedplace is a pointer defined at file scope. As such, it has
                static duration and is initialized to NULL. That means it does not
                point to memory you own.
                27 Small_Int i;
                28
                29 main(int argc,char * argv[])
                Implicit int has been removed from C99. Better to specify it
                explicitly as in
                int main(...
                30 {
                31 i = 2;
                32 markedplace->data.dp = NULL;
                Here you attempt to dereference markedplace via the -operator.
                Dereferencing a pointer that does not point to memory you own invokes
                undefined behavior.
                33 (Small_Int *)markedplace->data.dp = i;
                Wrong in so many so many different ways.

                You still cannot dereference markedplace as noted above.

                The -operator has higher precedence than cast operator. The left
                hand side is parsed as if it were (Small_Int *)(markedplace->data.dp).
                The cast does not change the type of markedplace->data.dp. If it did
                anything it would convert its value to the new type. Consequently,
                the expression does not represent an object into which you can store a
                value. (That is what the compiler is trying to tell you in the error
                message about an lvalue required.) So the answer to the implied
                question at the top of your post is "There is no way to cast the left
                operand of the assignment operator."

                If the left hand side could evaluate to an lvalue, it would have a
                pointer type. i is an integer. Assigning an integer to a pointer is
                a constraint violation requiring a diagnostic. In this case, even if
                the compiler were to generate the correct code to convert the value in
                i to a pointer, the result would be pretty much useless.
                34 }
                main returns an int. So do so.
                >
                >$ gcc type_cast.c
                >type_cast.c: In function 'main':
                >type_cast.c:33 : error: lvalue required as left operand of assignment
                >
                First you should insure that markedplace points to a structure.
                Alternately, you could change markedplace from a pointer to an actual
                struct by removing the * from its definition. Then you would replace
                all the -operators with . operators.

                Since data.dp is a void*, it is capable of holding the address of any
                object and there is an implicit conversion in both directions between
                pointers to void and pointers to any type of object. Therefore no
                cast is needed and your code should look something like
                markedplace->data.dp = &i;


                Remove del for email

                Comment

                Working...