tags:

views:

351

answers:

6

Please check out the following func and its output

void main()
{
    Distance d1;
    d1.setFeet(256);
    d1.setInches(2.2);

    char *p=(char *)&d1;
    *p=1;

    cout<< d1.getFeet()<< " "<< d1.getInches()<< endl;
}

The class Distance gets its values thru setFeet and setInches, passing int and float arguments respectively. It displays the values through through the getFeet and getInches methods.

However, the output of this function is 257 2.2. Why am I getting these values?

+13  A: 

This is a really bad idea:

char *p=(char *)&d1;
*p=1;

Your code should never make assumptions about the internal structure of the class. If your class had any virtual functions, for example, that code would cause a crash when you called them.

I can only conclude that your Distance class looks like this:

class Distance {
    short feet;
    float inches;
public:
    void setFeet(...
};

When you setFeet(256), it sets the high byte (MSB) to 1 (256 = 1 * 2^8) and the low byte (LSB) to 0. When you assign the value 1 to the char at the address of the Distance object, you're forcing the first byte of the short representing feet to 1. On a little-endian machine, the low byte is at the lower address, so you end up with a short with both bytes set to 1, which is 1 * 2^8 + 1 = 257.

On a big-endian machine, you would still have the value 256, but it would be purely coincidental because you happen to be forcing a value of 1 on a byte that would already be 1.

However, because you're using undefined behavior, depending on the compiler and the compile options, you might end up with literally anything. A famous expression from comp.lang.c is that such undefined behavior could "cause demons to fly out of your nose".

Tim Sylvester
+1 for the expression, did not know it :)
Matthieu M.
Demons flying out of my nose I can handle. It's when undefined behaviour produces the "expected" results that I'm afraid.
patros
+2  A: 

You are illegally munging memory via the 'p' pointer.

The output of the program is undefined; as you are directly manipulating memory that is owned by an object through a pointer of another type without regard to the underlying types.

Your code is somewhat like this:

struct Dist
{
    int     x;
    float   y;
};

union Plop
{
    Dist    s;  // Your class
    char    p;  // The type you are pretending to use via 'p'
};

int main()
{
    Plop    p;

    p.s.x   = 5;    // Set up the Dist structure.
    p.s.y   = 2.3;

    p.p     = 1;    // The value of s is now undefined.
                    // As you have scribbled over the memory used by s.
}
Martin York
Actually, OP's code's behavior need not necessarily be undefined. Accessing an object through the pointer to `char` is explicitly allowed by the standard.
avakar
@avakar That only makes sense if you use `offsetof` or similar to discover the actual address of a public member. Accessing the object's memory without discovering the member offset has to be undefined behavior or such internals as v-table pointers would not be possible.
Tim Sylvester
Yes, any POD can be accessed and modified through `char*`, but you don't know the representation of its members. Except when the first member is a `char`, the behavior is undefined when accessing the first member afterwards by its type even for PODs if have written a trap representation (so assuming the worst, it's always undefined). If not, the value is still unspecified since you don't know the mapping between bits and values of the member. If the first member is a char and if the struct is a POD, then it's perfectly valid code.
Johannes Schaub - litb
@avakar: Thats like saying poining a loaded gun at your own head is explicitly allowed by the law. True. But not a good idea.
Martin York
@litb: also I think if the first value is a `signed char` or `unsigned char`. Writing 1 to either of those has defined behaviour, and IIRC they aren't allowed to have trap representations either (and must be the same size as char).
Steve Jessop
Yes, *if* you write a trap representation, and then read it, then you are doing UB. But since those types cannot have traps (not sure about `signed char` here, though), this cannot happen for them, so you can safely read. But the value you will read will be unspecified (you are guaranteed that this will read *some* value, but i don't think the value is required to be anything in particular).
Johannes Schaub - litb
A: 

I assume you think doing *p = 1 will set one of the internal data members (presumably 'feet') in the Distance object. It may work, but (afaik) you've got no guarantees that the feet member is at the first address of the object, is of the correct size (unless its type is also char) or that it's aligned correctly.

If you want to do that why not make the 'feet' member public and do:

d1.feet = 1;
pxb
Or assign feet through setFeet() that the OP already has.
JeffH
Indeed, but there might be valid reasons he wants to directly modify the contents, and treat it more like a struct than a class (I appreciate there's very little difference between them in c++).
pxb
+1  A: 

The behaviour based on the code given is going to be very unpredictable. Setting the first byte of d1's data could potentially clobber a vptr, compiler-specific memory, the sign/exponent of a floating point value, or LSB or MSB of an integer, all depending on the definition of Distance.

Matt Joiner
A: 

Another thing, to comment on the program: don't use void main(). It isn't standard, and it offers you no benefits. It will make people not take you as seriously when asking C or C++ questions, and could cause programs to not compile, or not work properly.

The C++ Standard, in 3.6.1 paragraph 2, says that main() always returns int, although the implementation may offer variations with different arguments.

This would be a good time to break the habit. If you're learning from a book that uses void main(), the book is unreliable. See about getting another book, if only for reference.

David Thornley
A: 

It looks like you are new to programming and could use some help with basic concepts.

It's good that you are looking for that, but SO may not be the right place to get it.

Good luck.

Mike Dunlavey