Printf question.

Discussion in 'C Programming' started by praeiji, Dec 30, 2005.

  1. praeiji

    praeiji Guest

    Hi,

    I was wondering something today. The following code :

    unsigned char a = 200;
    char b = 200;
    printf( "%d %d", a, b );

    gives :

    200, -56

    How comes? I didn't tell printf that the first argument was unsigned
    and it detected it on its own. It doesn't seem possible with varargs.
    How is it possible?

    Thanks,
    praeiji, Dec 30, 2005
    #1
    1. Advertising

  2. praeiji

    Guest

    praeiji <> wrote:
    >
    > unsigned char a = 200;
    > char b = 200;
    > printf( "%d %d", a, b );
    >
    > gives :
    >
    > 200, -56
    >
    > How comes? I didn't tell printf that the first argument was unsigned
    > and it detected it on its own. It doesn't seem possible with varargs.
    > How is it possible?


    Both arguments get promoted to int before they are passed to printf()

    _Ico

    --
    :wq
    ^X^Cy^K^X^C^C^C^C
    , Dec 30, 2005
    #2
    1. Advertising

  3. praeiji

    praeiji Guest

    Thanks,

    But why are they typecasted to int? Does it come from gcc when it sees
    "%d" and the printf function?
    praeiji, Dec 30, 2005
    #3
  4. praeiji

    nelu Guest

    praeiji wrote:
    > Hi,
    >
    > I was wondering something today. The following code :
    >
    > unsigned char a = 200;
    > char b = 200;
    > printf( "%d %d", a, b );
    >
    > gives :
    >
    > 200, -56
    >
    > How comes? I didn't tell printf that the first argument was unsigned
    > and it detected it on its own. It doesn't seem possible with varargs.
    > How is it possible?
    >
    > Thanks,


    Conversion Argument Converted Default Pre-
    Specifier Type Value Base cision
    %d int x (int)x 10 1

    That means %d formats int. If you give it char and unsigned char it
    will convert them to int.
    nelu, Dec 30, 2005
    #4
  5. praeiji

    Jack Klein Guest

    On 30 Dec 2005 11:21:25 -0800, "praeiji" <> wrote
    in comp.lang.c:

    > Hi,
    >
    > I was wondering something today. The following code :
    >
    > unsigned char a = 200;
    > char b = 200;
    > printf( "%d %d", a, b );
    >
    > gives :
    >
    > 200, -56
    >
    > How comes? I didn't tell printf that the first argument was unsigned
    > and it detected it on its own. It doesn't seem possible with varargs.
    > How is it possible?
    >
    > Thanks,


    This has nothing to do with printf(), per se. It does not know the
    difference between the original objects providing the values.

    What you are seeing is the result of what the C standard calls the
    "default argument promotions". These occur when calling a function
    without a prototype in scope, or for the "..." arguments in a variadic
    function.

    In the case of integer types of lesser rank than int, the "integer
    promotions" occur. Since a signed int can hold the value 200, the
    value in the unsigned char 'a' is converted to the int value 200.

    On your particular system, chars have 8 bits and 'plain' char is
    signed. The binary representation of 200 in an 8-bit byte happens to
    be the same as the 8-bit 2's complement representation of -56, and
    that is the implementation-defined result of assigning the
    out-of-range value to a signed 'plain' char.

    The integer promotions take the 'plain' char value of -56 and convert
    it to an int value of -56.

    So the values of 200 and -56 are generated during argument evaluation,
    before printf() is called.

    On some platforms, char has more than 8 bits, and 200 would remain 200
    in a 'plain' char or signed char. On some platforms, 'plain' char is
    unsigned, not signed. On platforms with either of these
    characteristics, the output would be "200, 200".

    And on some platforms, the output would not appear at all because you
    did not add a final '\n'.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Dec 30, 2005
    #5
  6. praeiji

    praeiji Guest

    thank you :)

    Silly me, I'd never heard of the "integer promotions" before.
    praeiji, Dec 30, 2005
    #6
  7. praeiji

    Guest

    praeiji <> wrote:

    > But why are they typecasted to int? Does it come from gcc when it sees
    > "%d" and the printf function?


    No, they are not typecasted, but `promoted', which is not the same thing.
    Promotion is what happens when you call a function that has no prototype, or
    when a function with a variable number (variadic) of arguments like printf()
    is called. With promotion, all arguments are converted to a generic 'bigger'
    type: char and short to int, float to double.

    Ico

    --
    :wq
    ^X^Cy^K^X^C^C^C^C
    , Dec 30, 2005
    #7
  8. Jack Klein <> writes:
    > On 30 Dec 2005 11:21:25 -0800, "praeiji" <> wrote
    > in comp.lang.c:

    [...]
    >> unsigned char a = 200;
    >> char b = 200;
    >> printf( "%d %d", a, b );
    >>
    >> gives :
    >>
    >> 200, -56
    >>
    >> How comes? I didn't tell printf that the first argument was unsigned
    >> and it detected it on its own. It doesn't seem possible with varargs.
    >> How is it possible?

    [snip]

    > In the case of integer types of lesser rank than int, the "integer
    > promotions" occur. Since a signed int can hold the value 200, the
    > value in the unsigned char 'a' is converted to the int value 200.


    Correction: since a signed int can hold any value of type unsigned
    char, the value in the unsigned char 'a' is promoted to type int. The
    promoted type doesn't depend on the value that happens to be in the
    variable; it depends on which type can hold *any* possible value of
    the type.

    --
    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.
    Keith Thompson, Dec 30, 2005
    #8
  9. praeiji

    Flash Gordon Guest

    Keith Thompson wrote:
    > Jack Klein <> writes:
    >> On 30 Dec 2005 11:21:25 -0800, "praeiji" <> wrote
    >> in comp.lang.c:

    > [...]
    >>> unsigned char a = 200;
    >>> char b = 200;
    >>> printf( "%d %d", a, b );
    >>>
    >>> gives :
    >>>
    >>> 200, -56
    >>>
    >>> How comes? I didn't tell printf that the first argument was unsigned
    >>> and it detected it on its own. It doesn't seem possible with varargs.
    >>> How is it possible?

    > [snip]
    >
    >> In the case of integer types of lesser rank than int, the "integer
    >> promotions" occur. Since a signed int can hold the value 200, the
    >> value in the unsigned char 'a' is converted to the int value 200.

    >
    > Correction: since a signed int can hold any value of type unsigned
    > char, the value in the unsigned char 'a' is promoted to type int.


    <annoying pedant>
    What, even on a system with CHAR_BIT==16 and sizeof(int)==1 ?
    </annoying pedant>

    Of course, you are only likely to find such systems in the embedded
    world where you may well not have printf.

    > The
    > promoted type doesn't depend on the value that happens to be in the
    > variable; it depends on which type can hold *any* possible value of
    > the type.


    You are, of course, correct that is is purely a matter of type, not the
    value the variable happens to contain.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
    Flash Gordon, Dec 30, 2005
    #9
  10. wrote:
    >
    > praeiji <> wrote:
    >
    > > But why are they typecasted to int? Does it come from gcc when it sees
    > > "%d" and the printf function?

    >
    > No, they are not typecasted, but `promoted', which is not the same thing.
    > Promotion is what happens when you call a function that has no prototype, or
    > when a function with a variable number (variadic) of arguments like printf()
    > is called. With promotion, all arguments are converted to a generic 'bigger'
    > type: char and short to int, float to double.
    >

    Type promotion can also happen when you do mixed mode arithmetic.

    --
    +----------------------------------------------------------------+
    | Charles and Francis Richmond richmond at plano dot net |
    +----------------------------------------------------------------+
    Charles Richmond, Dec 31, 2005
    #10
  11. praeiji

    Jack Klein Guest

    On Fri, 30 Dec 2005 20:56:02 GMT, Keith Thompson <> wrote
    in comp.lang.c:

    > Jack Klein <> writes:
    > > On 30 Dec 2005 11:21:25 -0800, "praeiji" <> wrote
    > > in comp.lang.c:

    > [...]
    > >> unsigned char a = 200;
    > >> char b = 200;
    > >> printf( "%d %d", a, b );
    > >>
    > >> gives :
    > >>
    > >> 200, -56
    > >>
    > >> How comes? I didn't tell printf that the first argument was unsigned
    > >> and it detected it on its own. It doesn't seem possible with varargs.
    > >> How is it possible?

    > [snip]
    >
    > > In the case of integer types of lesser rank than int, the "integer
    > > promotions" occur. Since a signed int can hold the value 200, the
    > > value in the unsigned char 'a' is converted to the int value 200.

    >
    > Correction: since a signed int can hold any value of type unsigned
    > char, the value in the unsigned char 'a' is promoted to type int. The
    > promoted type doesn't depend on the value that happens to be in the
    > variable; it depends on which type can hold *any* possible value of
    > the type.


    Yes, thanks.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Dec 31, 2005
    #11
  12. praeiji

    Malcolm Guest

    "Flash Gordon" <> wrote
    >
    >> Correction: since a signed int can hold any value of type unsigned
    >> char, the value in the unsigned char 'a' is promoted to type int.

    >
    > <annoying pedant>
    > What, even on a system with CHAR_BIT==16 and sizeof(int)==1 ?
    > </annoying pedant>
    >
    > Of course, you are only likely to find such systems in the embedded world
    > where you may well not have printf.
    >

    But often you have vsprintf(), or you need to implement it.

    The whole language does begin to break down when we push the limits of
    ANSI's definition. For instance, should field-length parameters really be
    size_t s?
    Malcolm, Dec 31, 2005
    #12
  13. praeiji

    Eric Sosman Guest

    Charles Richmond wrote:
    > wrote:
    >
    >>praeiji <> wrote:
    >>
    >>
    >>>But why are they typecasted to int? Does it come from gcc when it sees
    >>>"%d" and the printf function?

    >>
    >>No, they are not typecasted, but `promoted', which is not the same thing.
    >>Promotion is what happens when you call a function that has no prototype, or
    >>when a function with a variable number (variadic) of arguments like printf()
    >>is called. With promotion, all arguments are converted to a generic 'bigger'
    >>type: char and short to int, float to double.
    >>

    >
    > Type promotion can also happen when you do mixed mode arithmetic.


    Or even unmixed-mode arithmetic:

    short x = 1, y = 2;
    short z = x + y; /* see the "int"? */

    --
    Eric Sosman
    lid
    Eric Sosman, Dec 31, 2005
    #13
  14. praeiji

    Jordan Abel Guest

    On 2005-12-31, Malcolm <> wrote:
    > "Flash Gordon" <> wrote
    >>
    >>> Correction: since a signed int can hold any value of type unsigned
    >>> char, the value in the unsigned char 'a' is promoted to type int.

    >>
    >> <annoying pedant>
    >> What, even on a system with CHAR_BIT==16 and sizeof(int)==1 ?
    >> </annoying pedant>
    >>
    >> Of course, you are only likely to find such systems in the embedded world
    >> where you may well not have printf.
    >>

    > But often you have vsprintf(), or you need to implement it.
    >
    > The whole language does begin to break down when we push the limits of
    > ANSI's definition. For instance, should field-length parameters really be
    > size_t s?


    You could take the cheap way out and do stuff along the lines of

    sprintf(format,"%%%d.%df",width,precision>=0?precision:0);

    c89 doesn't appear to provide for field-length parameters anyway - at
    least the draft i have doesn't.
    Jordan Abel, Dec 31, 2005
    #14
  15. praeiji

    Bliss Guest

    praeiji dropped $.02 in the slot and wrote:
    > Hi,
    >
    > I was wondering something today. The following code :
    >
    > unsigned char a = 200;
    > char b = 200;
    > printf( "%d %d", a, b );
    >
    > gives :
    >
    > 200, -56
    >
    > How comes? I didn't tell printf that the first argument was unsigned
    > and it detected it on its own. It doesn't seem possible with varargs.
    > How is it possible?


    That would happen if plain char on your machine is signed and char is
    eight bits wide. The assignment b = 200 makes b -56.

    Roger.
    Bliss, Jan 2, 2006
    #15
  16. Bliss wrote:
    > praeiji dropped $.02 in the slot and wrote:
    > > Hi,
    > >
    > > I was wondering something today. The following code :
    > >
    > > unsigned char a = 200;
    > > char b = 200;
    > > printf( "%d %d", a, b );
    > >
    > > gives :
    > >
    > > 200, -56
    > >
    > > How comes? I didn't tell printf that the first argument was
    > > unsigned and it detected it on its own. It doesn't seem
    > > possible with varargs. How is it possible?

    >
    > That would happen if plain char on your machine is signed and
    > char is eight bits wide. The assignment b = 200 makes b -56.


    Your conditions are necessary, but not strictly sufficient to make b
    receive the value of -56.

    As the value 200 is outside the range of an 8-bit signed
    plain char, the conversion is implementation defined.[*]
    Even adding the condition that signed char has twos
    complement representation is not sufficient to force a
    value of -56 for b since an implementation is still
    entitled to assign say 0 in such cases, if it chooses.

    You can say it likely yielded -56 because most implementations
    are two's complement and preserve the bitwise representation
    (albeit with trunction or sign extension) when performing
    conversions of an integer value which is outside the range of
    the target type.

    [*] C99 adds the possibility of an implementation defined signal.

    --
    Peter
    Peter Nilsson, Jan 2, 2006
    #16
    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. Edith Gross
    Replies:
    2
    Views:
    329
    =?iso-8859-1?Q?Juli=E1n?= Albo
    Nov 2, 2003
  2. ben
    Replies:
    4
    Views:
    601
    Martin Ambuhl
    Jun 26, 2004
  3. whatluo

    (void) printf vs printf

    whatluo, May 26, 2005, in forum: C Programming
    Replies:
    29
    Views:
    1,228
  4. azza

    printf affects following printf/s

    azza, Oct 17, 2010, in forum: C Programming
    Replies:
    0
    Views:
    426
  5. guru
    Replies:
    8
    Views:
    267
Loading...

Share This Page