Differences between pointers

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jason Curl

    Differences between pointers

    Hello,

    Just a clarification of the specification about the C-Standard's
    interpretation of pointers.

    I know that 'char *' and 'void *' are equivalent and that 'int *' may be
    different in representation to 'char *' (but most often there is no
    difference on modern compilers/machines).

    So if I define a function such as (e.g. often for callbacks)

    void foo(void *data);

    Then if I pass something that is a structure

    struct testing {
    int a;
    char b;
    };

    int main(void)
    {
    struct testing x;
    x.a = 1;
    x.b = 2;

    foo((void *)&x);
    return 0;
    }

    is this concept valid? If not, what would be a valid way to achieve
    portable results?

    Best Regards,
    Jason.
  • Jack Klein

    #2
    Re: Differences between pointers

    On Wed, 13 Apr 2005 06:11:02 +0200, Jason Curl
    <j_dot_curl@mot orola.com> wrote in comp.lang.c:
    [color=blue]
    > Hello,
    >
    > Just a clarification of the specification about the C-Standard's
    > interpretation of pointers.
    >
    > I know that 'char *' and 'void *' are equivalent and that 'int *' may be
    > different in representation to 'char *' (but most often there is no
    > difference on modern compilers/machines).
    >
    > So if I define a function such as (e.g. often for callbacks)
    >
    > void foo(void *data);
    >
    > Then if I pass something that is a structure
    >
    > struct testing {
    > int a;
    > char b;
    > };
    >
    > int main(void)
    > {
    > struct testing x;
    > x.a = 1;
    > x.b = 2;
    >
    > foo((void *)&x);[/color]

    The cast is unnecessary. The & operator takes the address of its
    operand yielding a value of pointer to type, in this case pointer to
    struct testing. In C, no cast is required to convert between pointer
    to void and pointer to any other object type, not in either direction.

    So rewrite this as:

    foo(&x);
    [color=blue]
    > return 0;
    > }
    >
    > is this concept valid? If not, what would be a valid way to achieve
    > portable results?
    >
    > Best Regards,
    > Jason.[/color]

    The concept is perfectly valid and portable as far as the code you
    wrote. Actually using the pointer is another matter. It must be
    converted to a pointer to object type before it can be used to
    actually read or write values.

    The only portable types it may be converted to are pointer to struct
    testing, or pointer to int, in which case it will point to the 'a'
    member of the testing structure.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c++-faq-lite/
    alt.comp.lang.l earn.c-c++

    Comment

    • Phenix Zhang

      #3
      Re: Differences between pointers

      Jason Curl wrote:
      [color=blue]
      > Hello,
      >
      > Just a clarification of the specification about the C-Standard's
      > interpretation of pointers.
      >
      > I know that 'char *' and 'void *' are equivalent and that 'int *' may be
      > different in representation to 'char *' (but most often there is no
      > difference on modern compilers/machines).
      >
      > So if I define a function such as (e.g. often for callbacks)
      >
      > void foo(void *data);
      >
      > Then if I pass something that is a structure
      >
      > struct testing {
      > int a;
      > char b;
      > };
      >
      > int main(void)
      > {
      > struct testing x;
      > x.a = 1;
      > x.b = 2;
      >
      > foo((void *)&x);
      > return 0;
      > }
      >
      > is this concept valid? If not, what would be a valid way to achieve
      > portable results?
      >
      > Best Regards,
      > Jason.[/color]
      Why don't you write your code like this ?
      void foo(struct testing *data)????

      --
      Just when you felt lonely, you began to miss me.
      When I was missing you, I falled into lonely.

      Comment

      • Richard Bos

        #4
        Re: Differences between pointers

        Jack Klein <jackklein@spam cop.net> wrote:
        [color=blue]
        > On Wed, 13 Apr 2005 06:11:02 +0200, Jason Curl
        > <j_dot_curl@mot orola.com> wrote in comp.lang.c:
        >[color=green]
        > > I know that 'char *' and 'void *' are equivalent[/color][/color]

        Well... almost. They're required to have identical representation and
        alignment, but only void * can be assigned to and from other object
        pointers without casting.
        [color=blue][color=green]
        > > So if I define a function such as (e.g. often for callbacks)
        > >
        > > void foo(void *data);
        > >
        > > Then if I pass something that is a structure
        > >
        > > struct testing {
        > > int a;
        > > char b;
        > > };
        > >
        > > int main(void)
        > > {
        > > struct testing x;
        > > x.a = 1;
        > > x.b = 2;
        > >
        > > foo((void *)&x);[/color]
        >
        > The cast is unnecessary.[/color]
        [color=blue]
        > The concept is perfectly valid and portable as far as the code you
        > wrote. Actually using the pointer is another matter. It must be
        > converted to a pointer to object type before it can be used to
        > actually read or write values.
        >
        > The only portable types it may be converted to are pointer to struct
        > testing, or pointer to int, in which case it will point to the 'a'
        > member of the testing structure.[/color]

        And a pointer to unsigned char, in which case it may be used to inspect
        the memory representation of the struct (which is implementation-
        specific, and may (probably will) include padding bytes).

        Richard

        Comment

        • Jason Curl

          #5
          Re: Differences between pointers

          Jack Klein wrote:[color=blue]
          > On Wed, 13 Apr 2005 06:11:02 +0200, Jason Curl
          > <j_dot_curl@mot orola.com> wrote in comp.lang.c:
          >
          >[color=green]
          >>Hello,
          >>
          >>Just a clarification of the specification about the C-Standard's
          >>interpretatio n of pointers.
          >>
          >>I know that 'char *' and 'void *' are equivalent and that 'int *' may be
          >>different in representation to 'char *' (but most often there is no
          >>difference on modern compilers/machines).
          >>
          >>So if I define a function such as (e.g. often for callbacks)
          >>
          >> void foo(void *data);
          >>
          >>Then if I pass something that is a structure
          >>
          >> struct testing {
          >> int a;
          >> char b;
          >> };
          >>
          >> int main(void)
          >> {
          >> struct testing x;
          >> x.a = 1;
          >> x.b = 2;
          >>
          >> foo((void *)&x);[/color]
          >
          >
          > The cast is unnecessary. The & operator takes the address of its
          > operand yielding a value of pointer to type, in this case pointer to
          > struct testing. In C, no cast is required to convert between pointer
          > to void and pointer to any other object type, not in either direction.
          >
          > So rewrite this as:
          >
          > foo(&x);
          >
          >[color=green]
          >> return 0;
          >> }
          >>
          >>is this concept valid? If not, what would be a valid way to achieve
          >>portable results?
          >>
          >>Best Regards,
          >>Jason.[/color]
          >
          >
          > The concept is perfectly valid and portable as far as the code you
          > wrote. Actually using the pointer is another matter. It must be
          > converted to a pointer to object type before it can be used to
          > actually read or write values.
          >
          > The only portable types it may be converted to are pointer to struct
          > testing, or pointer to int, in which case it will point to the 'a'
          > member of the testing structure.
          >[/color]
          Jack - because void* and int* can have a different internal
          representation, can the size of the pointers change also? Or does the
          C-spec state the size of the ptrs are the same?

          Can there be an esoteric machine (or even just a compiler) built that
          sizeof(void*)== 4 and sizeof(int*)==6 , so when the type cast is done,
          data is lost on the function call resulting in an invalid pointer when
          it's typecasted back from void* to int*?

          If this is really the case, would the solution that I use the signature:

          void foo(int*);

          and then I can have

          struct testing1 {
          int a;
          char b;
          };

          struct testing2 {
          int a;
          char *str;
          }

          and pass pointers to the structures typecasted to (int*)?

          I find this question important for implementing, say, generic message
          queues on embedded systems (where it's easy to have the first member of
          the struct an int, that defines the message, and the remaining data in
          the struct being the message).

          Thanks again.
          Jason.

          Comment

          • pete

            #6
            Re: Differences between pointers

            Phenix Zhang wrote:[color=blue]
            >
            > Jason Curl wrote:
            >[color=green]
            > > Hello,
            > >
            > > Just a clarification of the specification about the C-Standard's
            > > interpretation of pointers.
            > >
            > > I know that 'char *' and 'void *'
            > > are equivalent and that 'int *' may be
            > > different in representation to 'char *' (but most often there is no
            > > difference on modern compilers/machines).
            > >
            > > So if I define a function such as (e.g. often for callbacks)
            > >
            > > void foo(void *data);
            > >
            > > Then if I pass something that is a structure
            > >
            > > struct testing {
            > > int a;
            > > char b;
            > > };
            > >
            > > int main(void)
            > > {
            > > struct testing x;
            > > x.a = 1;
            > > x.b = 2;
            > >
            > > foo((void *)&x);
            > > return 0;
            > > }
            > >
            > > is this concept valid? If not, what would be a valid way to achieve
            > > portable results?
            > >
            > > Best Regards,
            > > Jason.[/color]
            > Why don't you write your code like this ?
            > void foo(struct testing *data)????[/color]

            That's what I think. It's not a generic function,
            meant to work with pointers to various different types of data.

            --
            pete

            Comment

            • Keith Thompson

              #7
              Re: Differences between pointers

              Jason Curl <j_dot_curl@mot orola.com> writes:
              [...][color=blue]
              > Jack - because void* and int* can have a different internal
              > representation, can the size of the pointers change also? Or does the
              > C-spec state the size of the ptrs are the same?[/color]

              I'm not Jack, but ...

              There's no requirement that void* and int* have to be the same type.
              [color=blue]
              > Can there be an esoteric machine (or even just a compiler) built that
              > sizeof(void*)== 4 and sizeof(int*)==6 , so when the type cast is done,
              > data is lost on the function call resulting in an invalid pointer when
              > it's typecasted back from void* to int*?[/color]

              I believe that conversion from int* to void* and back to int* is
              guaranteed to yield a value equal to the original value. (If that
              weren't the case, void* wouldn't be usable as a generic pointer type.)

              If int* and void* are of different sizes, it's more likely that void*
              is bigger. More information may be needed to point to any arbitrary
              byte than to point to an integer. For example, a raw machine address
              might point to a word, with a void* or char* consisting of a word
              pointer plus an offset.

              (I've never seen an implementation where int* and void* are of
              different sizes; I've used systems with native word poitenrs, but the
              offset for a void* or char* was stored in the unused high-order bits.)

              --
              Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
              San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
              We must do something. This is something. Therefore, we must do this.

              Comment

              • Flash Gordon

                #8
                Re: Differences between pointers

                Jason Curl wrote:

                <snip>
                [color=blue]
                > Jack - because void* and int* can have a different internal
                > representation, can the size of the pointers change also? Or does the
                > C-spec state the size of the ptrs are the same?[/color]

                I'm not aware of anything that says the pointer sizes have to be the
                same, but there are other guarantees that help you here...
                [color=blue]
                > Can there be an esoteric machine (or even just a compiler) built that
                > sizeof(void*)== 4 and sizeof(int*)==6 , so when the type cast is done,
                > data is lost on the function call resulting in an invalid pointer when
                > it's typecasted back from void* to int*?[/color]

                The standard guarantees that you can assign any pointer to an object to
                a pointer to void and then back and end up with a pointer to the
                original type. I.e this will always work:

                T foo;
                T *fooptr = &foo;
                void *vptr = fooptr;
                T *foo2ptr = vptr;
                if (fooptr == foo2ptr)
                puts("Executed on all conforming implementations ");

                Note that the above is not guaranteed for function pointers.
                [color=blue]
                > If this is really the case, would the solution that I use the signature:
                >
                > void foo(int*);
                >
                > and then I can have
                >
                > struct testing1 {
                > int a;
                > char b;
                > };
                >
                > struct testing2 {
                > int a;
                > char *str;
                > }
                >
                > and pass pointers to the structures typecasted to (int*)?
                >
                > I find this question important for implementing, say, generic message
                > queues on embedded systems (where it's easy to have the first member of
                > the struct an int, that defines the message, and the remaining data in
                > the struct being the message).[/color]

                Fortunately for you, there is another guarantee that further helps you
                here. With two struct definitions that share a common initial set of
                fields, i.e. the "int a" in your example above, those initial fields are
                guaranteed to have the same layout. I believe you are also guaranteed to
                have no padding before the *first* field.

                I may not be Jack, but I'm sure someone will correct me if I've made a
                mistake.
                --
                Flash Gordon
                Living in interesting times.
                Although my email address says spam, it is real and I read it.

                Comment

                • CBFalconer

                  #9
                  Re: Differences between pointers

                  Jason Curl wrote:[color=blue]
                  >
                  > Just a clarification of the specification about the C-Standard's
                  > interpretation of pointers.
                  >
                  > I know that 'char *' and 'void *' are equivalent and that 'int *'
                  > may be different in representation to 'char *' (but most often
                  > there is no difference on modern compilers/machines).
                  >
                  > So if I define a function such as (e.g. often for callbacks)
                  >
                  > void foo(void *data);
                  >
                  > Then if I pass something that is a structure
                  >
                  > struct testing {
                  > int a;
                  > char b;
                  > };
                  >
                  > int main(void)
                  > {
                  > struct testing x;
                  > x.a = 1;
                  > x.b = 2;
                  >
                  > foo((void *)&x);
                  > return 0;
                  > }
                  >
                  > is this concept valid? If not, what would be a valid way to achieve
                  > portable results?[/color]

                  It's fine. However the cast is unnecessary and can prevent the
                  compiler from flagging errors, so remove it. Then the foo
                  implementation should include:

                  void foo(void *data)
                  {
                  struct testing *dp = data;

                  /* code using dp, and not data */
                  }

                  and you will note there is no sign of a cast anywhere. All this
                  allows that void* pointer to pass through various levels of
                  software that don't care exactly what it points to, with only the
                  originator and destination actually caring (or knowing).

                  Removing the cast from the caller means that if you ever alter foo
                  to specify the parameter type more closely (i.e. as a non-void*)
                  you will get a compiler error. With the caller cast the error will
                  be ignored.

                  --
                  "If you want to post a followup via groups.google.c om, don't use
                  the broken "Reply" link at the bottom of the article. Click on
                  "show options" at the top of the article, then click on the
                  "Reply" at the bottom of the article headers." - Keith Thompson


                  Comment

                  • Richard Bos

                    #10
                    Re: Differences between pointers

                    Keith Thompson <kst-u@mib.org> wrote:
                    [color=blue]
                    > Jason Curl <j_dot_curl@mot orola.com> writes:
                    > [...][color=green]
                    > > Jack - because void* and int* can have a different internal
                    > > representation, can the size of the pointers change also? Or does the
                    > > C-spec state the size of the ptrs are the same?[/color]
                    >
                    > I'm not Jack, but ...
                    >
                    > There's no requirement that void* and int* have to be the same type.[/color]

                    Erm.

                    void * and int * _are_ not the same type. One is a pointer to void, the
                    other a pointer to int.

                    YM "the same size", I presume.
                    [color=blue][color=green]
                    > > Can there be an esoteric machine (or even just a compiler) built that
                    > > sizeof(void*)== 4 and sizeof(int*)==6 , so when the type cast is done,
                    > > data is lost on the function call resulting in an invalid pointer when
                    > > it's typecasted back from void* to int*?[/color]
                    >
                    > I believe that conversion from int* to void* and back to int* is
                    > guaranteed to yield a value equal to the original value.[/color]

                    'tis. Ditto for any other object pointer type: to void *, and back to
                    the _original_ type, must always work correctly. To void *, and "back"
                    to another type, need not work at all.
                    [color=blue]
                    > If int* and void* are of different sizes, it's more likely that void*
                    > is bigger.[/color]

                    More likely, but not guaranteed; but even when int * is larger, the
                    transfer through void * must still work. This means that a larger int *
                    must contain padding bits, but that's allowed.

                    Richard

                    Comment

                    • Keith Thompson

                      #11
                      Re: Differences between pointers

                      rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:[color=blue]
                      > Keith Thompson <kst-u@mib.org> wrote:[color=green]
                      >> Jason Curl <j_dot_curl@mot orola.com> writes:
                      >> [...][color=darkred]
                      >> > Jack - because void* and int* can have a different internal
                      >> > representation, can the size of the pointers change also? Or does the
                      >> > C-spec state the size of the ptrs are the same?[/color]
                      >>
                      >> I'm not Jack, but ...
                      >>
                      >> There's no requirement that void* and int* have to be the same type.[/color]
                      >
                      > Erm.
                      >
                      > void * and int * _are_ not the same type. One is a pointer to void, the
                      > other a pointer to int.
                      >
                      > YM "the same size", I presume.[/color]

                      D'oh! Yes, I meant the same size.

                      [...][color=blue][color=green]
                      >> If int* and void* are of different sizes, it's more likely that void*
                      >> is bigger.[/color]
                      >
                      > More likely, but not guaranteed; but even when int * is larger, the
                      > transfer through void * must still work. This means that a larger int *
                      > must contain padding bits, but that's allowed.[/color]

                      [Low-level nitpicking follows. Stop reading now if you value your
                      sanity.]

                      Basically correct, but strictly speaking the term "padding bits"
                      applies only to integer types. Also, it refers to a disinct subset of
                      the bits of a type representation, bits that don't contribute to the
                      value, but that doesn't necessarily apply in this case.

                      One off-the-wall example is that void* might be represented as a pure
                      binary machine address, and int* might be represented in biquinary
                      (7 bits per decimal digit). All the bits contribute to the value, so
                      there are no padding bits; it's just an inefficient representation.

                      Or if you prefer a more binary representation, you can double the size
                      with a mapping like:

                      00 --> 0001
                      01 --> 0010
                      10 --> 0100
                      11 --> 1000

                      This is, of course, totally unrealistic, though I suspect some
                      versions of the mythical DS9K use this representation (or something
                      even worse).

                      The standard talks about padding bits for integer types because it
                      places strong constraints on how integers are represented. There are
                      virtually no constraints on pointer representations (other than that
                      they're made of bits and bytes and can, like any type, be viewed as
                      arrays of unsigned char).

                      --
                      Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                      San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                      We must do something. This is something. Therefore, we must do this.

                      Comment

                      • Peter Nilsson

                        #12
                        Re: Differences between pointers

                        Keith Thompson wrote:[color=blue]
                        > rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:[color=green]
                        > > Keith Thompson <kst-u@mib.org> wrote:[color=darkred]
                        > >> If int* and void* are of different sizes, it's more likely that[/color][/color][/color]
                        void*[color=blue][color=green][color=darkred]
                        > >> is bigger.[/color]
                        > >
                        > > More likely, but not guaranteed; but even when int * is larger, the
                        > > transfer through void * must still work. This means that a larger[/color][/color]
                        int *[color=blue][color=green]
                        > > must contain padding bits, but that's allowed.[/color]
                        >
                        > [Low-level nitpicking follows. Stop reading now if you value your
                        > sanity.]
                        >
                        > Basically correct, but strictly speaking the term "padding bits"
                        > applies only to integer types.[/color]

                        Since we're nitpicking ;), it's not as if the committee _invented_ the
                        term 'padding bits'. The term is not in italics within C99. Indeed, the
                        term 'padding' is used exclusively as a qualification without explicit
                        definition.

                        --
                        Peter

                        Comment

                        • pete

                          #13
                          Re: Differences between pointers

                          Peter Nilsson wrote:[color=blue]
                          >
                          > Keith Thompson wrote:[color=green]
                          > > rlb@hoekstra-uitgeverij.nl (Richard Bos) writes:[color=darkred]
                          > > > Keith Thompson <kst-u@mib.org> wrote:
                          > > >> If int* and void* are of different sizes,
                          > > >> it's more likely that void*
                          > > >> is bigger.
                          > > >
                          > > > More likely, but not guaranteed;
                          > > > but even when int * is larger, the
                          > > > transfer through void * must still work.
                          > > > This means that a larger int *
                          > > > must contain padding bits, but that's allowed.[/color]
                          > >
                          > > [Low-level nitpicking follows. Stop reading now if you value your
                          > > sanity.]
                          > >
                          > > Basically correct, but strictly speaking the term "padding bits"
                          > > applies only to integer types.[/color]
                          >
                          > Since we're nitpicking ;), it's not as if the committee _invented_ the
                          > term 'padding bits'.
                          > The term is not in italics within C99. Indeed, the
                          > term 'padding' is used exclusively as a qualification without explicit
                          > definition.[/color]

                          C does not allow bitwise operations
                          on any other types besides integer types.
                          No other types besides integer types, are described in
                          the standard as being decomposable into various kinds of bits.
                          Whether or not your pointer has a sign bit, is off topic
                          with regard to portable C programming.

                          --
                          pete

                          Comment

                          Working...