Accessing private member of a class through type-casting

Discussion in 'C++' started by dragoncoder, Apr 7, 2006.

  1. dragoncoder

    dragoncoder Guest

    Consider the code

    class A {
    private:
    int a;
    };

    int main(void) {
    A x;
    int* ptr = (int*)&x;
    *x = 10;
    return 0;
    }

    I understand that I can not change the private attributes of a class,
    but what does standard have to say about the code above?
    dragoncoder, Apr 7, 2006
    #1
    1. Advertising

  2. dragoncoder

    Noah Roberts Guest

    dragoncoder wrote:
    > Consider the code
    >
    > class A {
    > private:
    > int a;
    > };
    >
    > int main(void) {
    > A x;
    > int* ptr = (int*)&x;
    > *x = 10;
    > return 0;
    > }
    >
    > I understand that I can not change the private attributes of a class,
    > but what does standard have to say about the code above?


    That its behavior is undefined. It might work...it might not...it
    might end the world as you know it...undefined.
    Noah Roberts, Apr 7, 2006
    #2
    1. Advertising

  3. dragoncoder

    Tomás Guest

    dragoncoder posted:

    > Consider the code
    >
    > class A {
    > private:
    > int a;
    > };
    >
    > int main(void) {
    > A x;


    You've create an object of the type "A". This object contains within it
    an object of the type "int".


    > int* ptr = (int*)&x;


    The expression "&x" is of the type "A*" (leaving out const). You have
    used an old C-style cast to turn it into an "int*". This is illegal.

    Even if your code was legal, you make the assumption that the address of
    "x" is equal to the address of "x.a". I'm not sure if the Standard gives
    any such guarantee. If the object was of a class which contained virtual
    methods, your code would be even less reliable.

    > *x = 10;


    The value of "x" is undefined, so your the behaviour of the above
    statement is undefined.

    > return 0;
    > }



    -Tomás
    Tomás, Apr 7, 2006
    #3
  4. dragoncoder

    Noah Roberts Guest

    dragoncoder wrote:

    > int main(void) {
    > A x;
    > int* ptr = (int*)&x;
    > *x = 10;


    Oh, I missed something here. *ptr = 10; would have been undefined. *x
    = 10 doesn't compile as A doesn't have an operator*.

    BTW, (int*)&x is totally legal. It is a C-style cast and as is the
    case with all C-style casts it can do things unexpectedly. What this
    resolves to is a reinterpret_cast<int*>(&x). This is of course legal
    but has undefined results. A static_cast would be illegal and using
    the C++ casting mechanism would have warned you about the undefined
    nature of the cast...this is why C-Style casts are bad.
    Noah Roberts, Apr 7, 2006
    #4
  5. dragoncoder

    Tomás Guest


    >> *x = 10;


    I presume that should have been:

    *ptr = 10;


    -Tomás
    Tomás, Apr 7, 2006
    #5
  6. dragoncoder

    red floyd Guest

    Tomás wrote:
    > dragoncoder posted:
    >
    >> Consider the code
    >>
    >> class A {
    >> private:
    >> int a;
    >> };
    >>
    >> int main(void) {
    >> A x;

    >
    > You've create an object of the type "A". This object contains within it
    > an object of the type "int".
    >
    >
    >> int* ptr = (int*)&x;

    >
    > The expression "&x" is of the type "A*" (leaving out const). You have
    > used an old C-style cast to turn it into an "int*". This is illegal.
    >

    Not quite illegal, merely undefined.

    >
    >> *x = 10;

    >
    > The value of "x" is undefined, so your the behaviour of the above
    > statement is undefined.
    >
    >> return 0;
    >> }

    >
    >
    > -Tomás
    red floyd, Apr 7, 2006
    #6
  7. dragoncoder

    Pete C Guest

    dragoncoder wrote:
    > Consider the code
    >
    > class A {
    > private:
    > int a;
    > };
    >
    > int main(void) {
    > A x;
    > int* ptr = (int*)&x;
    > *x = 10;
    > return 0;
    > }
    >
    > I understand that I can not change the private attributes of a class,
    > but what does standard have to say about the code above?


    If I turn my car to drive the wrong way up a one-way street, it obeys
    me! Hah! Stupid car. Sometimes I will even get where I want to go.
    Pete C, Apr 7, 2006
    #7
  8. dragoncoder

    dragoncoder Guest

    Tomás wrote:
    > >> *x = 10;

    >
    > I presume that should have been:
    >
    > *ptr = 10;
    >

    Yes, i actually meant to write *ptr = 10; Apologies for the same.
    >
    > -Tomás
    dragoncoder, Apr 7, 2006
    #8
  9. dragoncoder

    Noah Roberts Guest

    Pete C wrote:
    > dragoncoder wrote:
    > > Consider the code
    > >
    > > class A {
    > > private:
    > > int a;
    > > };
    > >
    > > int main(void) {
    > > A x;
    > > int* ptr = (int*)&x;
    > > *x = 10;
    > > return 0;
    > > }
    > >
    > > I understand that I can not change the private attributes of a class,
    > > but what does standard have to say about the code above?

    >
    > If I turn my car to drive the wrong way up a one-way street, it obeys
    > me! Hah! Stupid car. Sometimes I will even get where I want to go.


    But the result is pretty well defined even if there are a couple
    alternative end scenarios. It is also, as apposed to the code in
    question, quite illegal.

    ;)
    Noah Roberts, Apr 7, 2006
    #9
  10. dragoncoder

    dragoncoder Guest

    If I correct the code so that *x = 10 becomes *ptr = 10, even then is
    the behaviour undefined ?

    I want to know which step I am doing wrong ? Is it illegal to assign
    (int*)&x to ptr ? Or is it illegal to do *ptr = 10 ? I am confused. The
    corrected is posted again.

    class A {
    private:
    int a;
    };

    int main(void) {
    A x;
    int* ptr = (int*)&x;
    *ptr = 10;
    return 0;
    }
    dragoncoder, Apr 7, 2006
    #10
  11. dragoncoder wrote:
    > If I correct the code so that *x = 10 becomes *ptr = 10, even then is
    > the behaviour undefined ?


    Yes.

    > I want to know which step I am doing wrong ? Is it illegal to assign
    > (int*)&x to ptr ? Or is it illegal to do *ptr = 10 ? I am confused.


    It is illegal to use 'ptr' after obtaining it by reinterpret_cast'ing
    it from '&x'. The Standard says that if two pointers are unrelated (and
    they are), all you can do with the pointer is to cast it back and get
    the same pointer value iff the alignment requirements are no less strict
    for the destination ("temporary") pointer. Something like that, anyway.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Apr 7, 2006
    #11
  12. dragoncoder

    Noah Roberts Guest

    Victor Bazarov wrote:
    > dragoncoder wrote:
    > > If I correct the code so that *x = 10 becomes *ptr = 10, even then is
    > > the behaviour undefined ?

    >
    > Yes.
    >
    > > I want to know which step I am doing wrong ? Is it illegal to assign
    > > (int*)&x to ptr ? Or is it illegal to do *ptr = 10 ? I am confused.

    >
    > It is illegal to use 'ptr' after obtaining it by reinterpret_cast'ing
    > it from '&x'.


    The result is undefined...it is not illegal to do so.
    Noah Roberts, Apr 7, 2006
    #12
  13. dragoncoder

    Noah Roberts Guest

    dragoncoder wrote:
    > If I correct the code so that *x = 10 becomes *ptr = 10, even then is
    > the behaviour undefined ?


    It becomes undefined. *x = 10 is illegal and won't compile.
    Noah Roberts, Apr 7, 2006
    #13
  14. dragoncoder

    Phlip Guest

    dragoncoder wrote:

    > int* ptr = (int*)&x;
    > *ptr = 10;


    Let me try to explain the illegality.

    (int*) in C is the same as reinterpret_cast<> in C++. C++ only defines the
    result of such a cast if it casts a pointer to what the data really is.

    Such typecasts make the compiler pretend that a class A is an int. This
    would be legal:

    A * p = (A *)(int *) &x; // both could use reinterpret_cast

    Your code might do anything (including appear to work correctly) because you
    don't know if the address of A::a is the same as the address of its A. So
    your cast might not end up pointing to an int.

    Your code will most likely appear to work, because a compiler has no reason
    to put any other data in A except the int a. Because the behavior is
    undefined, it might break if you change something about your compiler, or
    class A. For example, if you add a virtual destructor, your code will most
    likely fail.

    --
    Phlip
    http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
    Phlip, Apr 7, 2006
    #14
  15. dragoncoder

    Tomás Guest

    Phlip posted:

    > dragoncoder wrote:
    >
    >> int* ptr = (int*)&x; *ptr = 10;

    >
    > Let me try to explain the illegality.
    >
    > (int*) in C is the same as reinterpret_cast<> in C++.



    Not really. "reinterpret_cast" can't cast pointers to functions if I recall
    correctly, while C-style casts can.

    > C++ only defines
    > the result of such a cast if it casts a pointer to what the data really
    > is.
    >
    > Such typecasts make the compiler pretend that a class A is an int. This
    > would be legal:
    >
    > A * p = (A *)(int *) &x; // both could use reinterpret_cast



    I don't think this should work. The two types, "A*" and "int*" are
    unrelated. Yes, they are both pointers, but what they point to are totally
    different. In three steps, here's what you're doing:

    1: Start off with the expression "&x" which is of type "A*".
    2: You then use a C-style cast to turn it into an "int*". The Standard
    doesn't guarantee that an "int*" can reliably hold the address of an object
    of type "A", so the value might get corrupted.
    3: Now you use a C-style cast again to turn it into an "A*", but the value
    may already have been corrupted.

    It's quite like the following:

    double k = 32.2342;

    double f = (double) (int) k;

    f will have the value of 32 rather than 32.2342.


    > Your code might do anything (including appear to work correctly)
    > because you don't know if the address of A::a is the same as the
    > address of its A. So your cast might not end up pointing to an int.



    I believe this is true.


    -Tomás
    Tomás, Apr 7, 2006
    #15
  16. dragoncoder

    Noah Roberts Guest

    Phlip wrote:
    > dragoncoder wrote:
    >
    > > int* ptr = (int*)&x;
    > > *ptr = 10;

    >
    > Let me try to explain the illegality.
    >
    > (int*) in C is the same as reinterpret_cast<> in C++. C++ only defines the
    > result of such a cast if it casts a pointer to what the data really is.
    >
    > Such typecasts make the compiler pretend that a class A is an int. This
    > would be legal:
    >
    > A * p = (A *)(int *) &x; // both could use reinterpret_cast
    >
    > Your code might do anything (including appear to work correctly) because you
    > don't know if the address of A::a is the same as the address of its A. So
    > your cast might not end up pointing to an int.
    >
    > Your code will most likely appear to work, because a compiler has no reason
    > to put any other data in A except the int a. Because the behavior is
    > undefined, it might break if you change something about your compiler, or
    > class A. For example, if you add a virtual destructor, your code will most
    > likely fail.


    You are explaining undefined behavior. The word "illegal" never
    appears in the standard that I know of and at least not in the
    definitions section. I would take "illegal" to mean against the
    standard, which would equate to ill-formed. Such a cast is not against
    the standard. The standard explicitly defines the mapping of such cast
    as implementation-defined and that "a pointer to an object can be
    explicitly cast to a pointer to an object of a different type." This
    means that the cast of A* to int* is _allowed_ by the standard and the
    result is /implementation-defined/.

    The use of the resulting pointer is as undefined as using any other
    random pointer. As such, the standard imposes no requirements
    whatsoever so the construct is still not dissallowed or "illegal" by
    any definition of the word I know of.
    Noah Roberts, Apr 7, 2006
    #16
  17. dragoncoder

    Phlip Guest

    Noah Roberts wrote:

    > This
    > means that the cast of A* to int* is allowed by the standard and the
    > result is implementation-defined.


    I'm aware, in our culture, that "illegal" does not necessarily mean "you
    shouldn't do it".

    class A {
    public:
    A() { assert((int)this == (int)&a); }
    private:
      int a;
    };

    There. If that assertion would pass, then the cast is "legal". And note that
    "legal" also does not appear in The Standard, yack yack yack, etc.

    --
    Phlip
    http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
    Phlip, Apr 7, 2006
    #17
  18. dragoncoder

    Noah Roberts Guest

    Tomás wrote:
    > Phlip posted:
    >
    > > dragoncoder wrote:
    > >
    > >> int* ptr = (int*)&x; *ptr = 10;

    > >
    > > Let me try to explain the illegality.
    > >
    > > (int*) in C is the same as reinterpret_cast<> in C++.

    >
    >
    > Not really. "reinterpret_cast" can't cast pointers to functions if I recall
    > correctly, while C-style casts can.


    See 5.2.10. P4 states you can convert a pointer to an int. P5 states
    you can convert a function pointer to another function pointer.
    >
    > > C++ only defines
    > > the result of such a cast if it casts a pointer to what the data really
    > > is.
    > >
    > > Such typecasts make the compiler pretend that a class A is an int. This
    > > would be legal:
    > >
    > > A * p = (A *)(int *) &x; // both could use reinterpret_cast

    >
    >
    > I don't think this should work. The two types, "A*" and "int*" are
    > unrelated. Yes, they are both pointers, but what they point to are totally
    > different.


    The behavior of the above expression is actually well defined. Given
    certain requirements the result is the same as &x. Failing to meet
    those requirements has "unspecified" results.

    In three steps, here's what you're doing:
    >
    > 1: Start off with the expression "&x" which is of type "A*".
    > 2: You then use a C-style cast to turn it into an "int*". The Standard
    > doesn't guarantee that an "int*" can reliably hold the address of an object
    > of type "A", so the value might get corrupted.
    > 3: Now you use a C-style cast again to turn it into an "A*", but the value
    > may already have been corrupted.
    >
    > It's quite like the following:
    >
    > double k = 32.2342;
    >
    > double f = (double) (int) k;
    >
    > f will have the value of 32 rather than 32.2342.


    Actually, it is nothing like that. double and int have well defined
    conversions. That particular C-style cast is the same as two
    static_cast operations. The previous is two reinterpret_cast
    operations. Totally different casts...again, this is the problem with
    c-style casting...they look the same but are not.
    Noah Roberts, Apr 7, 2006
    #18
  19. dragoncoder

    Phlip Guest

    Noah Roberts wrote:

    >> double k = 32.2342;
    >>
    >> double f = (double) (int) k;
    >>
    >> f will have the value of 32 rather than 32.2342.

    >
    > Actually, it is nothing like that.  double and int have well defined
    > conversions


    Let's try "well defined _lossy_ conversions".

    I'm beginning to suspect (because you read The Standard for me), that
    pointer conversions are well-defined as lossless.

    --
    Phlip
    http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
    Phlip, Apr 7, 2006
    #19
  20. dragoncoder

    Noah Roberts Guest

    Phlip wrote:
    > Noah Roberts wrote:
    >
    > > This
    > > means that the cast of A* to int* is allowed by the standard and the
    > > result is implementation-defined.

    >
    > I'm aware, in our culture, that "illegal" does not necessarily mean "you
    > shouldn't do it".
    >


    The word illegal has a well defined definition in the English language,
    let us look to it:

    1. Prohibited by law.
    2. Prohibited by official rules: an illegal pass in football.
    3. Unacceptable to or not performable by a computer: an illegal
    operation.

    #1 does not apply - law in this case being the standard.
    #2 also similarly to #1 does not apply.

    The standard _allows_ the cast so by elimination it is not prohibited
    ;)

    #3 is the only possibilty however since the operation IS performable I
    don't see how it applies.

    The standard _allows_ the cast...all implementations therefore have to
    allow it and be able to perform it. The standard does not specify how.

    So, you can redefine words if you wish but then you may as well be
    speaking in Greek...or Martian for that matter.
    Noah Roberts, Apr 7, 2006
    #20
    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. Steven T. Hatton
    Replies:
    2
    Views:
    413
    tom_usenet
    Aug 16, 2004
  2. DaveLessnau
    Replies:
    3
    Views:
    424
    Howard
    May 16, 2005
  3. heyo
    Replies:
    3
    Views:
    900
    Dan Pop
    Apr 1, 2004
  4. Mike
    Replies:
    9
    Views:
    363
  5. Hicham Mouline
    Replies:
    1
    Views:
    352
    Vladyslav Lazarenko
    Mar 27, 2009
Loading...

Share This Page