c prog -plz explain

Discussion in 'C Programming' started by SAHIL MAHLA, Mar 10, 2014.

  1. SAHIL MAHLA

    SAHIL MAHLA Guest

    #include <stdio.h>
    void incme(double *p)
    {
    *p += 1;
    }

    int main(void)
    {
    int i = 1;
    double j=i;
    incme((double*)&i);
    printf("%d,%g",i,j);
    return 0;
    }

    The output is :

    0,1

    I feel it should be :

    2,1


    Thanks in advance!!!
     
    SAHIL MAHLA, Mar 10, 2014
    #1
    1. Advertisements

  2. You posted this exact same program, with different output, in the other
    thread. See Barry Schwarz's followup.

    And please take the time to spell out words: "please" rather than "plz".
    Silly abbreviations like that just make your text more difficult to
    read.
     
    Keith Thompson, Mar 10, 2014
    #2
    1. Advertisements

  3. SAHIL MAHLA

    Lew Pitcher Guest

    Why do you feel that the program should print
    2,1
    as it's results? Please tell us your reasoning, so that we can assist you in
    your understanding of the actual performance of your program code.

    For what it's worth, others have told you *why* you get the results you get,
    and *why* those results are questionable. Please re-read those responses,
    and reconsider your "feeling".
     
    Lew Pitcher, Mar 10, 2014
    #3
  4. This is a different program. This one is undefined because it converts
    an 'int *' to a 'double *' and passes that to the incme function.

    <snip>
     
    Ben Bacarisse, Mar 10, 2014
    #4
  5. Ah, but this "different" program was also posted in the other thread!
    Sorry for the noise.
     
    Ben Bacarisse, Mar 10, 2014
    #5
  6. SAHIL MAHLA

    SAHIL MAHLA Guest

    Hi Pitcher ,

    It's because we are typecasting i's address into a double* and then passing it to the incre() function. I know there is some issue with the typecasting itself.Passing like this is illegal ...is it???.....and my apologies for the silly abbrevations.
     
    SAHIL MAHLA, Mar 11, 2014
    #6
  7. SAHIL MAHLA

    SAHIL MAHLA Guest

    Hi Ben ,

    Yes we are converting a int* to double*.Could you generalize this with a rule why that is undefined.
     
    SAHIL MAHLA, Mar 11, 2014
    #7
  8. SAHIL MAHLA

    Ian Collins Guest

    Please trim you quotes and cleanup all the unwanted blank lines that
    awful google interface adds!

    You are "casting", not "typecasting".

    You are passing the address of an int, which probably has a size of 4 to
    a function expecting the address of a double, which probably has a size
    of 8. Consider what happens when 8 bytes are written to something 4
    bytes long...
     
    Ian Collins, Mar 11, 2014
    #8
  9. SAHIL MAHLA

    James Kuyper Guest

    A pointer to an object of one type can be converted to a pointer to an
    object with a completely unrelated type. However, if the pointer is not
    correctly aligned for the new type, the behavior of the conversion is
    undefined. (6.3.2.3p7) That could apply here, but it's not the most
    serious problem you face.

    The really serious problem is that most objects have an effective type
    (the only exception is dynamically allocated memory that has not yet
    been accessed using a pointer to a non-character type). If you attempt
    to access an object with one types, using an lvalue of a different type,
    it is called type punning. The result of type punning is usually
    undefined behavior. In this case, the effective type of 'i' is the same
    as it's declared type, 'int'. The expression *p is an lvalue of type
    double. Therefore, attempting to access the memory set aside to hold
    'i', using the expression *p, has undefined behavior.

    It is possible to use type punning safely. However, unless one of the
    two types involved is a character type, they must be closely related
    types, and 'int' is completely unrelated to 'double'. The precise rules
    are given in 6.5p7, but until you've learned those rules, the safest
    course is to avoid type punning.

    The basic reason for this rule is simple. Any object in C is represented
    by a series of bytes. For each object type, there is some precise rule
    that connects the value of each byte, and the value represented by that
    object, and it's generally a completely different rule for objects of
    different types. Type punning takes bytes that represented one value
    according to the rules for one type, and reinterprets them as if they
    represented a value according to the rules of a different type. This
    obviously can't work if the new type is larger than the original type,
    but even if they are the same size, it can fail, in some cases
    catastrophically. C's rules define the cases where you can portably rely
    upon type punning to work in some useful fashion.
     
    James Kuyper, Mar 11, 2014
    #9
  10. SAHIL MAHLA

    Kaz Kylheku Guest

    Yes. The rule is written in a document called ISO 9899 ("International
    Standard -- Programming Languages -- C").

    It was first published in 1990 (ISO 9899:1990) and describes a language called C90.
    It was updated to ISO 9899:1999 (C99), and 2011 (C11).

    If you read the standard, you will learn about all kinds of rules.

    It's really too complicated (and more importantly inefficient) to lecture about
    in a series of Usenet articles to complete newbies. Why don't you read the document,
    and then if you have questions, then it makes for a better discussion
    than "spoon feed me the rules", know what I mean?

    The rule which applies here is that an object shall not be accessed through an
    lvalue which is not its declared type (or a const/volatile qualified version of
    its declared type). An object of type int being accessed as if it were an object
    of type double results in undefined behavior.

    C is a strongly typed language. It has the concept of type: that an operation
    of the correct type must be applied to a datum for well-defined behavior. C has
    considerable translation-time type checking in it to support its type system,
    but when you use casts, especially for conversions among pointer types, you can
    defeat the type system and write programs which break the rules, but do not
    produce any diagnostics when compiled, and even make an executable.
     
    Kaz Kylheku, Mar 11, 2014
    #10
  11. SAHIL MAHLA

    Kaz Kylheku Guest

    Never mind the type casting being illega.

    Have you considerd that the type double and the type int do not even have the
    same size? (They might, but often they do not. A common size for int is 32
    bits nowadays, and a double is often 64 bits.)

    What do you think happens when you pass a pointer to 32 bytes of storage
    to a function which treats that as 64 bytes of storage?
    Of course, that function stomps on memory outside of the object.

    The code could well crash. What if incme overwrites the return address on the
    stack, so that when it tries to return back to main, it jumps into nowhere
    land, resulting in an access violation or illegal instruction trap or something
    of that sort?

    Listen, you better start replacing "I feel" with "I think", or find another
    hobby.

    Then, have you considered byte order issues? Suppose that the previous issue is
    not a problem. Although incme stomps over memory beyond the boundaries of i,
    let's suppose there is no problem because, let's say that that memory is just
    some unused padding space or whatever. There is still the problem that on
    some machines, values are laid out with the least significant bits at the base
    address. On other machines, values are placed with the most significant bits
    at the base address. This means that the int object i, if it is smaller than
    double (like 32 bits versus 64), could correspond to the upper half of double,
    where the sign and exponent are, or it could correspond to the lower half,
    where there are mantissa bits.

    Then there is the issue that incrementing a floating-point value by 1.0 is
    completely different from incrementing an integer by 1.

    Consider that if you add 1.0 to some really huge number like 1.0E+256,
    it doesn't change at all, because 1.0 is too small in comparison.

    However, if you add 1.0 to a really small number (close to zero) like
    1.0E-256, the result is just 1.0 because the really small number
    vanishes next to 1.0.

    Which bits of the floating-point value are affected when 1.0 is added
    to it (if any) and in what ways depends on the value. Adding 1.0
    might change the exponent field, or it might not. It could change
    the most significant bits of the mantissa, or the least significant
    bits, or none at all.

    Adding 1 to a postive integer is (in the absence of overflow) a purely
    binary operation. The least significant bit increments, and if that
    overflows, the next bit increments, and so on.

    The two operations are not related at all, and so if you perform a floating
    point increment on an integer or vice versa, you can get some very strange
    results.
     
    Kaz Kylheku, Mar 11, 2014
    #11
  12. SAHIL MAHLA

    Kaz Kylheku Guest

    Are you saying that I couldn't be here if I didn't have a day job?

    Or that ... this *is* my day job?

    Must be the second thing; the first is not known to be a significant barrier to
    Usenet participation.

    You don't get much income around here, but today we have "incme".
    Double star, too!
    I've been here since 1994 or 1995, so it must have been before then.
     
    Kaz Kylheku, Mar 11, 2014
    #12
  13. SAHIL MAHLA

    BartC Guest

    Because ints and doubles have a completely different binary representation.

    You might be /casting/ a pointer to int, to a pointer to double, but you are
    /type-punning/ what it points to. (You can't do an in-place cast of a
    pointer's target value.)

    The result will be meaningless unless you have a clue as to what you are
    doing, and do it properly. It can also cause problems (not just wrong
    results), if doubles are 8 bytes and ints are 4 bytes, because the *p+=1
    line might cause 8 bytes to updated at i, but i only has 4 bytes reserved
    for it.

    You don't need to read 700 pages of C specification to know that you cannot
    tell what will happen!
     
    BartC, Mar 11, 2014
    #13
  14. SAHIL MAHLA

    Lew Pitcher Guest

    What effect do you think that
    (double*)&i
    has on
    i
    ?

    In other words, what do you think that the "typecasting" (sic) does?
    Does it affect the storage type? Does "typecasting" a
    pointer to an integer
    to a
    pointer to a double precision floating point
    change the allocation of the thing pointed to from
    integer
    to
    double precision floating point
    ?
    No one is going to arrest you for it; there is no law against it.

    And "typecasting" (sic), as a tool, does not violate any requirements of the
    C language.

    But, just as a stick of dynamite can cause unintended damage when used
    incorrectly, "typecasting" (sic) also has it's dangerous side. It is not in
    the facility, but in it's use, that the danger occurs. And, your use
    of "typecasting" (sic) shows that you not only do not understand what it
    does, you have a misconception that has resisted all our attempts here to
    correct.
    Don't apologize. Just stop.

    You may have noticed my use of quotes and the editor's note "sic" when I use
    your word "typecasting". Computer programs are literal; they do not
    tolerate typographic errors, creative spelling, or incorrect terms.
    Programmers tend to become pedantic regarding the misuse of terminology and
    intentional misuse of grammer or syntax.

    The term is "casting", not "typecasting". True, a "cast" changes the "type"
    of a value (a *value*, not an *object*), but to call the construct
    a "typecast" is just wrong.
     
    Lew Pitcher, Mar 11, 2014
    #14
  15. An analogy. Think of a pointer as a handle -- a literal handle. Your
    car has a handbrake and a gearbox:

    handbreak brake = 1; // handbrake is on
    gearbox gbox = 3; // car is in 3rd gear

    The pointer &b is the handbrake lever -- it's attached to the actual
    brake. &g is the gear stick -- attached to the gear box. You can do
    gearbox-like things using a handle to a gearbox object, and you can do
    brake-like things using a handbrake handle. But writing:

    gearbox *stick = (gearbox *)&brake;

    is like making something that looks like a gear stick and attaching it
    to the brakes. Trying the usual action to put the car into 4th using
    this handle will just break stuff.
     
    Ben Bacarisse, Mar 11, 2014
    #15
  16. SAHIL MAHLA

    Ken Brody Guest

    [...]

    "I took my box of salt, and with a marker I crossed out 'salt' and wrote
    'sugar'. How come my tea tastes funny?"

    Just because you told the compiler to treat the pointer-to-int "&i" as if it
    were a pointer-to-double doesn't mean that what it points to really *is* a
    double.
     
    Ken Brody, Mar 11, 2014
    #16
  17. Sahil: If you're new to the language, I suggest you'll have better luck
    taking something you want to do and then figuring out how to do it,
    rather than starting with some (in this case questionable) code and then
    trying to figure out how it behaves and why.

    Yet another silly analogy: If you have a hammer, you should probably try
    to learn how to drive nails with it rather than starting out by asking
    what happens if you try to drive screws with it. You'll have plenty of
    opportunity to screw things up once you've mastered the basics.

    And again, let me recommend http://www.c-faq.com/ as an excellent
    resource (though as the name implies it's a collection of questions and
    answers, not a tutorial).
     
    Keith Thompson, Mar 11, 2014
    #17
  18. (snip)
    It would help if Sahil explained any previous programming experience.

    I can imagine someone with years of experience in other languages
    suddenly being surprised by the way C works, but also someone with no
    experience at all in other langauges.

    Explaining the reason why things work the way they do is different
    in the two cases.

    I didn't start with C until some years of programming, including
    enough assembly programming that I was used to thinking about
    addresses of things. (Though it took me a little while with my
    first assembly programs to remember which address was doing what.)

    (snip)

    -- glen
     
    glen herrmannsfeldt, Mar 11, 2014
    #18
  19. SAHIL MAHLA

    Kaz Kylheku Guest

    But that type of experience can also make some people more convinced
    about what something "should" do in C.

    The reason why explaining the reasons is different for the two cases
    is that in the case of the fresh newbie, you just have to explain it.

    In the case of the experienced newbie, you have to explain it,
    and furthermore, argue it ad nauseum. :)
     
    Kaz Kylheku, Mar 11, 2014
    #19
  20. SAHIL MAHLA

    Jorgen Grahn Guest

    For the record, I sometimes say "typecast" too. Picked it up 25 years
    ago or so, probably from my teachers. I'm tempted to suggest that it
    should be tolerated as a nickname ...

    /Jorgen
     
    Jorgen Grahn, Mar 12, 2014
    #20
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.