Casts

Discussion in 'C Programming' started by jacob navia, Jun 23, 2007.

  1. jacob navia

    jacob navia Guest

    Hi

    I am still writing my tutorial book about C. Here is the section about
    casts. I would be interested in your opinions about this. Some people
    have definite views about this subject ("never use casts") some others
    (like me) are more "liberal" in this subject. I would be interested
    in any feedback.

    jacob
    -------------------------------------------------------------------
    Casts
    A cast expression is the transformation of an object from one type to
    another. For instance, a common need is to transform double precision
    numbers into integers. This is specified like this:
    double d;
    ....
    (int)d
    In this case, the cast needs to invoke run time code to make the actual
    transformation. In other cases there is no code emitted at all. For
    instance in:
    void *p;
    ....
    (char *)p;
    Transforming one type of pointer into another needs no code at all at
    run-time in most implementations.

    When to use casts

    A cast can be useful to avoid unnecessary operations. For instance,
    given the declarations:

    double double_value;
    int integer_value;

    If you write

    integer_value /= double_value;

    The integer is promoted to double to do the division, then the result is
    converted to integer again. With a cast however, the unnecessary
    promotions can be avoided:

    integer_value /= (int)double_value;

    You can use a cast expression in another context, to indicate the type
    of a composite constant literal. For instance:
    typedef struct tagPerson {
    char Name[75];
    int age;
    } Person;

    void process(Person *);
    ....
    process(&(Person){“Mary Smith” , 38});
    This is one of the new features of C99. The literal should be enclosed
    in braces, and it should match the expected structure. This is just
    “syntactic sugar” for the following:

    Person __998815544ss = { “Mary Smith”, 38};
    process(&__998815544ss);

    The advantage is that now you are spared that task of figuring out a
    name for the structure since the compiler does that for you. Internally
    however, that code represents exactly what happens inside lcc-win32.

    When not to use casts

    Casts, as any other of the constructs above, can be misused. In general,
    they make almost impossible to follow the type hierarchy automatically.
    C is weakly typed, and most of the “weakness” comes from casts expressions.

    ----------------------------------------------------------------------
    jacob navia, Jun 23, 2007
    #1
    1. Advertising

  2. jacob navia

    Eric Sosman Guest

    jacob navia wrote:
    > [...]
    > A cast can be useful to avoid unnecessary operations. For instance,
    > given the declarations:
    >
    > double double_value;
    > int integer_value;
    >
    > If you write
    >
    > integer_value /= double_value;
    >
    > The integer is promoted to double to do the division, then the result is
    > converted to integer again. With a cast however, the unnecessary
    > promotions can be avoided:
    >
    > integer_value /= (int)double_value;


    It would be worth mentioning that the modified expression
    may produce a different value than the original. For example,
    consider integer_value=10 and double_value=3.5, where the
    original code calculates 2 and the revised code calculates 3.
    (Even better: consider double_value=0.1 ...)

    > You can use a cast expression in another context, to indicate the type
    > of a composite constant literal. For instance:
    > typedef struct tagPerson {
    > char Name[75];
    > int age;
    > } Person;
    >
    > void process(Person *);
    > ...
    > process(&(Person){“Mary Smith” , 38});


    This is not a cast, so it doesn't belong in a tutorial
    about casts. (Except, perhaps, to explain that it is not
    a cast despite a faint and superficial syntactic resemblance.)

    --
    Eric Sosman
    lid
    Eric Sosman, Jun 23, 2007
    #2
    1. Advertising

  3. "jacob navia" <> wrote in message
    news:467d891c$0$5071$...
    > Hi
    >
    > I am still writing my tutorial book about C. Here is the section about
    > casts. I would be interested in your opinions about this
    > void process(Person *);
    > ...
    > process(&(Person){“Mary Smith” , 38});
    > This is one of the new features of C99. Internally however, that code
    > represents exactly what happens inside lcc-win32.
    >

    I think you should either write a C89 tutorial, a C99 tutorial, or an
    lcc-win32 tutorial. I don't see the point of discussing C99 constructs and
    then how lcc-win implements them, if the reader is sitting at a C89
    compiler.

    It also changes the situation. If a cast is part of the syntax for assigning
    literal structures, then obviously it modifies whatever you migth want to
    say about "C casts".

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
    Malcolm McLean, Jun 23, 2007
    #3
  4. jacob navia

    jacob navia Guest

    Eric Sosman wrote:
    > jacob navia wrote:
    >> [...]
    >> A cast can be useful to avoid unnecessary operations. For instance,
    >> given the declarations:
    >>
    >> double double_value;
    >> int integer_value;
    >>
    >> If you write
    >>
    >> integer_value /= double_value;
    >>
    >> The integer is promoted to double to do the division, then the result
    >> is converted to integer again. With a cast however, the unnecessary
    >> promotions can be avoided:
    >>
    >> integer_value /= (int)double_value;

    >
    > It would be worth mentioning that the modified expression
    > may produce a different value than the original. For example,
    > consider integer_value=10 and double_value=3.5, where the
    > original code calculates 2 and the revised code calculates 3.
    > (Even better: consider double_value=0.1 ...)
    >


    Thanks. That is a very bad example as I see.

    Better use += as in
    integer_value += (int)double_value;

    Thanks for that.


    >> You can use a cast expression in another context, to indicate the type
    >> of a composite constant literal. For instance:
    >> typedef struct tagPerson {
    >> char Name[75];
    >> int age;
    >> } Person;
    >>
    >> void process(Person *);
    >> ...
    >> process(&(Person){“Mary Smith” , 38});

    >
    > This is not a cast, so it doesn't belong in a tutorial
    > about casts. (Except, perhaps, to explain that it is not
    > a cast despite a faint and superficial syntactic resemblance.)
    >


    You are right again.
    The standard says in a footnote

    Note that this differs from a cast expression.
    For example, a cast specifies a conversion to scalar types
    or void only, and the result of a cast expression is not an lvalue.

    I had not even seen that. Thanks

    jacob
    jacob navia, Jun 23, 2007
    #4
  5. jacob navia said:

    <snip>

    > Casts
    > A cast expression is the transformation of an object from one type to
    > another.


    No, it isn't. It is the transformation of a *value* from one type to
    another.

    <snip>

    > For instance in:
    > void *p;
    > ...
    > (char *)p;


    I can't think of a single good reason for casting a void * to a char *.

    > When to use casts
    >
    > A cast can be useful to avoid unnecessary operations. For instance,
    > given the declarations:
    >
    > double double_value;
    > int integer_value;
    >
    > If you write
    >
    > integer_value /= double_value;
    >
    > The integer is promoted to double to do the division, then the result
    > is converted to integer again. With a cast however, the unnecessary
    > promotions can be avoided:
    >
    > integer_value /= (int)double_value;


    ....at the cost of a conversion to int, so the saving isn't as great as
    you are leading the reader to believe.

    <snipped: a point that Eric has already discussed elsethread>

    You've completely failed to mention the (admittedly very few) places
    where casts are actually a good idea.


    > When not to use casts
    >
    > Casts, as any other of the constructs above, can be misused. In
    > general, they make almost impossible to follow the type hierarchy
    > automatically. C is weakly typed, and most of the ?weakness? comes
    > from casts expressions.


    You might want to get a proofreader onto that paragraph.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Jun 23, 2007
    #5
  6. jacob navia <> writes:
    > I am still writing my tutorial book about C. Here is the section
    > about casts. I would be interested in your opinions about this. Some
    > people
    > have definite views about this subject ("never use casts") some others
    > (like me) are more "liberal" in this subject. I would be interested
    > in any feedback.
    >
    > jacob
    > -------------------------------------------------------------------
    > Casts
    > A cast expression is the transformation of an object from one type to
    > another.


    Why do you use the word "transformation" when the word "conversion"
    already exists and is in common use?

    It's not correct to say that a cast *is* a conversion (or
    tranformation); rather, a cast *specifies* a conversion. Conversions
    can occur without the use of a cast.

    The operand of a cast is an expression, not necessarily an object.

    > For instance, a common need is to transform double precision
    > numbers into integers. This is specified like this:
    > double d;
    > ...
    > (int)d
    > In this case, the cast needs to invoke run time code to make the
    > actual transformation. In other cases there is no code emitted at
    > all. For instance in:
    > void *p;
    > ...
    > (char *)p;
    > Transforming one type of pointer into another needs no code at all at
    > run-time in most implementations.
    >
    > When to use casts
    >
    > A cast can be useful to avoid unnecessary operations. For instance,
    > given the declarations:
    >
    > double double_value;
    > int integer_value;
    >
    > If you write
    >
    > integer_value /= double_value;
    >
    > The integer is promoted to double to do the division, then the result
    > is converted to integer again. With a cast however, the unnecessary
    > promotions can be avoided:
    >
    > integer_value /= (int)double_value;


    Saying that the operation is "unnecessary" implies that this is just a
    matter of performance. In fact, depending on the values of
    double_value and integer_value, the cast can cause the expression to
    yield a different result. It's a matter of correctness, and depending
    on the requirements, adding the cast might break correct code.

    > You can use a cast expression in another context, to indicate the type
    > of a composite constant literal. For instance:
    > typedef struct tagPerson {
    > char Name[75];
    > int age;
    > } Person;
    >
    > void process(Person *);
    > ...
    > process(&(Person){“Mary Smith” , 38});


    Your quotation marks are showing up as "\223" and "\224". Use
    ordinary ASCII quotation marks, not whatever (Windows-specific?)
    characters you're using here.

    > This is one of the new features of C99. The literal should be enclosed
    > in braces, and it should match the expected structure. This is just
    > “syntactic sugar” for the following:
    >
    > Person __998815544ss = { “Mary Smith”, 38};
    > process(&__998815544ss);


    That's not a cast, it's a compound literal, a separate kind of
    expression. (For it to be a cast expression, the operand would have
    to be an expression; the stuff enclosed in braces is not by itself a
    valid expression.) The syntactic coincidence that it happens to
    include a type name in parentheses doesn't make it a cast, any more
    than sizeof(int) is a cast.

    > The advantage is that now you are spared that task of figuring out a
    > name for the structure since the compiler does that for
    > you. Internally however, that code represents exactly what happens
    > inside lcc-win32.


    Is this tutorial going to be specific to lcc-win32?

    > When not to use casts
    >
    > Casts, as any other of the constructs above, can be misused. In
    > general, they make almost impossible to follow the type hierarchy
    > automatically. C is weakly typed, and most of the “weakness”
    > comes from casts expressions.


    That's now how I'd put it; I might comment further after I've had time
    to think about it.

    Briefly, though, the real problem with casts is that they often carry
    an implicit message to the compiler of "I know what I'm doing, don't
    bother me with warnings". Very often, this isn't the case, and the
    result is errors that aren't diagnosed by the compiler.

    You don't mention another case where casts are appropriate: coercing
    an argument to a variadic function (such as printf) to the required
    type. For non-variadic functions, if you have a prototype in scope,
    this coercion will usually be done automatically. For variadic
    functions, the compiler lacks enough information to determine the
    proper type, so it's up to the programmer.

    --
    Keith Thompson (The_Other_Keith) <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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jun 23, 2007
    #6
  7. jacob navia

    jacob navia Guest

    Keith Thompson wrote:
    > Why do you use the word "transformation" when the word "conversion"
    > already exists and is in common use?


    Looked like synonyms to me. Granted, I changed that.

    >
    > It's not correct to say that a cast *is* a conversion (or
    > tranformation); rather, a cast *specifies* a conversion. Conversions
    > can occur without the use of a cast.
    >
    > The operand of a cast is an expression, not necessarily an object.


    All expressions return a result object... and that object is converted.
    Conversions can only act in objects whose values are converted
    isn't it?

    Or are we getting into philosophy??? :)

    [snip]

    >
    > Briefly, though, the real problem with casts is that they often carry
    > an implicit message to the compiler of "I know what I'm doing, don't
    > bother me with warnings". Very often, this isn't the case, and the
    > result is errors that aren't diagnosed by the compiler.
    >
    > You don't mention another case where casts are appropriate: coercing
    > an argument to a variadic function (such as printf) to the required
    > type. For non-variadic functions, if you have a prototype in scope,
    > this coercion will usually be done automatically. For variadic
    > functions, the compiler lacks enough information to determine the
    > proper type, so it's up to the programmer.
    >


    You are right.

    I added:

    Another case when casts are necessary occurs when passing arguments to a
    variadic function. Since the type of the arguments can’t be known by the
    compiler, it is necessary to cast a value to its exact expected type
    (double to float for example), so that the arguments are converted to
    the exact types the variadic function expects.

    For instance

    float f;

    printf("%Lg\n",(long double)f);

    The printf function expects a long double (format Lg). We need to
    convert our float f into a long double to match the expectations of
    printf.
    jacob navia, Jun 23, 2007
    #7
  8. jacob navia

    Guillaume Guest

    Richard Heathfield wrote:
    > I can't think of a single good reason for casting a void * to a char *.


    If you want to dereference it as a char *, maybe.
    Guillaume, Jun 23, 2007
    #8
  9. jacob navia

    jacob navia Guest

    Richard Heathfield wrote:
    >> For instance in:
    >> void *p;
    >> ...
    >> (char *)p;

    >
    > I can't think of a single good reason for casting a void * to a char *.


    int c = *((char *)p);
    jacob navia, Jun 23, 2007
    #9
  10. jacob navia

    jacob navia Guest

    Richard Heathfield wrote:
    > jacob navia said:
    >
    >> Richard Heathfield wrote:
    >>>> For instance in:
    >>>> void *p;
    >>>> ...
    >>>> (char *)p;
    >>> I can't think of a single good reason for casting a void * to a char
    >>> *.

    >> int c = *((char *)p);

    >
    > I still can't think of a single *good* reason for casting a void * to a
    > char *.
    >


    And why the above is not a good reason?

    You would write:

    char *cp = p;
    int c = *cp;

    Or how would you do that?
    jacob navia, Jun 23, 2007
    #10
  11. In article <>,
    Richard Heathfield <> wrote:

    >> If you want to dereference it as a char *, maybe.

    >
    >If I want to do that, I'll do this first:
    >
    >char *p = vp;
    >
    >Temps are cheap, and easy to read.



    As usual, readability is in the eye of the beholder. Using a
    temporary variable will use up vertical space, which I generally find
    reduces readability (because it reduces what fits on a page). In this
    case, I think *(char *)vp is a simple and common enough idiom that
    it's not worth the extra space.

    -- Richard

    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
    Richard Tobin, Jun 23, 2007
    #11
  12. jacob navia said:

    > Richard Heathfield wrote:
    >>> For instance in:
    >>> void *p;
    >>> ...
    >>> (char *)p;

    >>
    >> I can't think of a single good reason for casting a void * to a char
    >> *.

    >
    > int c = *((char *)p);


    I still can't think of a single *good* reason for casting a void * to a
    char *.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Jun 23, 2007
    #12
  13. Guillaume <"grsNOSPAM at NOTTHATmail dot com"> said:

    > Richard Heathfield wrote:
    >> I can't think of a single good reason for casting a void * to a char
    >> *.

    >
    > If you want to dereference it as a char *, maybe.


    If I want to do that, I'll do this first:

    char *p = vp;

    Temps are cheap, and easy to read.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Jun 23, 2007
    #13
  14. jacob navia said:

    > Keith Thompson wrote:


    <snip>

    >> The operand of a cast is an expression, not necessarily an object.

    >
    > All expressions return a result object...


    Expressions don't return anything. My C89 draft does occasionally
    mention operators returning values, and functions can certainly return
    values, but expressions don't return anything. They do, however, *have*
    a value.

    <snip>

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Jun 23, 2007
    #14
  15. jacob navia

    jacob navia Guest

    Richard Heathfield wrote:
    > Guillaume <"grsNOSPAM at NOTTHATmail dot com"> said:
    >
    >> Richard Heathfield wrote:
    >>> I can't think of a single good reason for casting a void * to a char
    >>> *.

    >> If you want to dereference it as a char *, maybe.

    >
    > If I want to do that, I'll do this first:
    >
    > char *p = vp;
    >
    > Temps are cheap, and easy to read.
    >


    No they are not.

    If the declaration of the temp is 76 lines before
    you have to look it up, then come back to see why you use
    a temporary variable, then discover that is not used anywhere else
    and that temp is just a variable to avoid a cast.

    Writing a smaller piece of code like

    int c = *((char *)p);

    is immediately clear what you are doing.
    jacob navia, Jun 23, 2007
    #15
  16. jacob navia

    jacob navia Guest

    Richard Heathfield wrote:
    > jacob navia said:
    >
    >> Richard Heathfield wrote:
    >>> jacob navia said:
    >>>
    >>>> Richard Heathfield wrote:
    >>>>>> For instance in:
    >>>>>> void *p;
    >>>>>> ...
    >>>>>> (char *)p;
    >>>>> I can't think of a single good reason for casting a void * to a
    >>>>> char *.
    >>>> int c = *((char *)p);
    >>> I still can't think of a single *good* reason for casting a void * to
    >>> a char *.
    >>>

    >> And why the above is not a good reason?

    >
    > Because it's difficult to read, for one thing. Because it can be unsafe,
    > for another. Because it's pointless, for a third.
    >
    >> You would write:
    >>
    >> char *cp = p;
    >> int c = *cp;
    >>
    >> Or how would you do that?

    >
    > If p points to a properly aligned int, I'd do this:
    >
    > int *ip = p;
    >
    > and then I'd use *ip, or define an int and assign *ip to it.
    >

    Note that my conversion was different:
    int c = *((char *)p);

    i.e. I am reading a byte from the void *;

    But in matters of taste there is no absolute rules.

    I will mention your viewpoint in the tutorial.
    jacob navia, Jun 23, 2007
    #16
  17. jacob navia said:

    > Richard Heathfield wrote:
    >> jacob navia said:
    >>
    >>> Richard Heathfield wrote:
    >>>>> For instance in:
    >>>>> void *p;
    >>>>> ...
    >>>>> (char *)p;
    >>>> I can't think of a single good reason for casting a void * to a
    >>>> char *.
    >>> int c = *((char *)p);

    >>
    >> I still can't think of a single *good* reason for casting a void * to
    >> a char *.
    >>

    >
    > And why the above is not a good reason?


    Because it's difficult to read, for one thing. Because it can be unsafe,
    for another. Because it's pointless, for a third.

    >
    > You would write:
    >
    > char *cp = p;
    > int c = *cp;
    >
    > Or how would you do that?


    If p points to a properly aligned int, I'd do this:

    int *ip = p;

    and then I'd use *ip, or define an int and assign *ip to it.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Jun 23, 2007
    #17
  18. jacob navia

    jacob navia Guest

    Richard Tobin wrote:
    > In article <>,
    > Richard Heathfield <> wrote:
    >
    >>> If you want to dereference it as a char *, maybe.

    >> If I want to do that, I'll do this first:
    >>
    >> char *p = vp;
    >>
    >> Temps are cheap, and easy to read.

    >
    >
    > As usual, readability is in the eye of the beholder.


    Yes. I will mention Mr Heathfield viewpoint in the tutorial.
    I do not agree though.

    > Using a
    > temporary variable will use up vertical space, which I generally find
    > reduces readability (because it reduces what fits on a page). In this
    > case, I think *(char *)vp is a simple and common enough idiom that
    > it's not worth the extra space.
    >
    >


    absolutely correct
    jacob navia, Jun 23, 2007
    #18
  19. jacob navia

    Guillaume Guest

    jacob navia wrote:
    > A cast can be useful to avoid unnecessary operations.


    Introducing casts, in a C tutorial, as an optimization technique seems
    quite bizarre to me.
    Talking about optimization in any introductory material is a very bad
    idea IMO. "Premature optimization is the root of all evil." At best, it
    is just distracting the novice from mastering the basics.

    That said, it is doubtful that your claim be valid on most modern
    platforms. It may even be misleading, and again IMO, it would be a bad
    introduction on optimization as well.

    Unfortunately, your example with a cast was not even a correct
    equivalent of the original statement, as others have pointed out.

    Casts should be used to insure correctness of expressions in respect to
    the intended result - not to compromise it.
    Guillaume, Jun 23, 2007
    #19
  20. jacob navia

    jacob navia Guest

    Guillaume wrote:
    > jacob navia wrote:
    >> A cast can be useful to avoid unnecessary operations.

    >
    > Introducing casts, in a C tutorial, as an optimization technique seems
    > quite bizarre to me.
    > Talking about optimization in any introductory material is a very bad
    > idea IMO. "Premature optimization is the root of all evil." At best, it
    > is just distracting the novice from mastering the basics.
    >
    > That said, it is doubtful that your claim be valid on most modern
    > platforms. It may even be misleading, and again IMO, it would be a bad
    > introduction on optimization as well.
    >
    > Unfortunately, your example with a cast was not even a correct
    > equivalent of the original statement, as others have pointed out.
    >
    > Casts should be used to insure correctness of expressions in respect to
    > the intended result - not to compromise it.


    Yes, the example was wrong.

    Maybe this speaks against casts, but they are part of the language
    and I have to treat that part isn't it?

    I am not promoting casts for optimizations, I just wanted some
    example for a cast usage, and I did not find anything better. By
    changing the /= to += I hope I fixed the example, even if it is
    not a very good one.
    jacob navia, Jun 23, 2007
    #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. =?Utf-8?B?Q2hyaXMgRGF2b2xp?=

    Web casts in ASP.Net

    =?Utf-8?B?Q2hyaXMgRGF2b2xp?=, Oct 19, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    497
    clintonG
    Oct 19, 2005
  2. cgbusch
    Replies:
    2
    Views:
    322
    Sudsy
    Jul 8, 2003
  3. Joona I Palaste

    Needless casts?

    Joona I Palaste, Apr 24, 2004, in forum: Java
    Replies:
    15
    Views:
    678
    Icemerth
    Apr 25, 2004
  4. Dan Upton

    checking casts

    Dan Upton, Nov 29, 2005, in forum: Java
    Replies:
    4
    Views:
    715
    Chris Smith
    Dec 1, 2005
  5. Wenjie

    C++ casts on zero

    Wenjie, Aug 17, 2003, in forum: C++
    Replies:
    11
    Views:
    654
    Wenjie
    Aug 24, 2003
Loading...

Share This Page