Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #41226 > unrolled thread

why printf("%d", arg) works with arg of type int, short, char

Started byjononanon@googlemail.com
First post2014-03-01 01:29 -0800
Last post2014-03-01 18:55 +0000
Articles 20 on this page of 26 — 14 participants

Back to article view | Back to comp.lang.c


Contents

  why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:29 -0800
    Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:42 -0800
      Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:54 -0800
        Re: why printf("%d", arg) works with arg of type int, short, char Barry Schwarz <schwarzb@dqel.com> - 2014-03-01 07:21 -0800
          Re: why printf("%d", arg) works with arg of type int, short, char gazelle@shell.xmission.com (Kenny McCormack) - 2014-03-01 15:51 +0000
            Re: why printf("%d", arg) works with arg of type int, short, char Richard <rgrdev_@gmail.com> - 2014-03-01 17:50 +0100
              Re: why printf("%d", arg) works with arg of type int, short, char gazelle@shell.xmission.com (Kenny McCormack) - 2014-03-01 18:36 +0000
    Re: why printf("%d", arg) works with arg of type int, short, char Melzzzzz <mel@zzzzz.invalid> - 2014-03-01 11:22 +0100
      Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 02:39 -0800
      Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 19:44 -0800
    Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 02:34 -0800
      Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 02:49 -0800
        Re: why printf("%d", arg) works with arg of type int, short, char James Kuyper <jameskuyper@verizon.net> - 2014-03-01 09:10 -0500
      Re: why printf("%d", arg) works with arg of type int, short, char <william@wilbur.25thandClement.com> - 2014-03-01 15:38 -0800
        Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 19:47 -0800
          Re: why printf("%d", arg) works with arg of type int, short, char <william@wilbur.25thandClement.com> - 2014-03-01 21:12 -0800
          Re: why printf("%d", arg) works with arg of type int, short, char Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2014-03-02 07:47 -0700
            Re: why printf("%d", arg) works with arg of type int, short, char Kaz Kylheku <kaz@kylheku.com> - 2014-03-02 20:53 +0000
              Re: why printf("%d", arg) works with arg of type int, short, char jgk@panix.com (Joe keane) - 2014-03-04 00:23 +0000
                Re: why printf("%d", arg) works with arg of type int, short, char Kaz Kylheku <kaz@kylheku.com> - 2014-03-04 00:33 +0000
                  Re: why printf("%d", arg) works with arg of type int, short, char glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-03-04 00:45 +0000
                  Re: why printf("%d", arg) works with arg of type int, short, char jgk@panix.com (Joe keane) - 2014-03-05 04:07 +0000
                    Re: why printf("%d", arg) works with arg of type int, short, char Barry Schwarz <schwarzb@dqel.com> - 2014-03-05 10:07 -0800
    Re: why printf("%d", arg) works with arg of type int, short, char "BartC" <bc@freeuk.com> - 2014-03-01 11:12 +0000
      Re: why printf("%d", arg) works with arg of type int, short, char Eric Sosman <esosman@comcast-dot-net.invalid> - 2014-03-01 10:54 -0500
        Re: why printf("%d", arg) works with arg of type int, short, char glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-03-01 18:55 +0000

Page 1 of 2  [1] 2  Next page →


#41226 — why printf("%d", arg) works with arg of type int, short, char

Fromjononanon@googlemail.com
Date2014-03-01 01:29 -0800
Subjectwhy printf("%d", arg) works with arg of type int, short, char
Message-ID<fc5dad84-08d7-4c7b-bd56-5ce49b177b1b@googlegroups.com>
Hi there!

Check this out -> the following code always works:

printf("%d %d %d", (char)'\1', (short)2, 3);
// prints: 1 2 3

So a conversion specifier of %d works with type int, or "SMALLER" integer-types (short or char) !!!

Why does this work??
Is my explanation correct? 




->
With printf("%d", (char) '\1')
the argument 1 lands on the stack not as char parameter, but as a parameter promoted to int, and the library code that handles the access to the parameter uses va_arg(ap, int) to access it. You can never use va_arg(ap, char) -> that would distroy a consistent handling of the stack-parameters!


When handling parameters on the stack, the size from one parameter to the next is never smaller than an int. (Even when NOT using variable arguments. Right? -> ref in C-std??)
Is this called argument promotion?


Demo:
/* 
demonstration that char on stack nonetheless occupies the space of an int!
Not only does it occupy the space of an int, but all bytes comprising that int are set correctly! not just the single byte corresponding the the char.
(How does one call this: argument promotion????
 Or is this part of integer promotion of a literal????)
*/
int func(char a, char b, char c) 
{
  const char *p = &a;
  printf("a=%d\n"
         "b=%d\n"
         "c=%d\n", p[0],
                   p[-(int)sizeof(int)], 
                   p[-(int)sizeof(int) * 2]); 
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
   If you want to do something like this portable, please use stdarg.h instead!
*/
}

Now, since printf("%d", arg) with its variable argument list, is implemented in the C library with stdarg.h's va_arg(ap, type)
and type may not be a "smaller" type than int, it so happens that the particular code for handling the conversion specifier "%d" uses va_arg(ap, int).


And that's the explanation!

Is it correct?






Can someone point out relevant parts of the C11 standard, that show that this handling of parameters in the stack must never occupy space of less than sizeof(int)??
And: ahhh... is this a issue of handling the stack; OR part of integer promotion of char-literals?? Two separate issues, or one and the same??







Examples with questions:
1)
printf("%d", '\1');

Here '\1' is promoted to int (integer promotion) and then put on the stack as integer?


2)
printf("%d", (char)'\1');

Does normal integer promotion of the literal char occur here? I think no.
Here a different type of promotion occurs, which is the one of handling the parameter stack??



I realize that I'm a bit confused, and may have things half-correct or so...?
Can someone give a good explanation.
Thanks so much!!

J.

[toc] | [next] | [standalone]


#41229

Fromjononanon@googlemail.com
Date2014-03-01 01:42 -0800
Message-ID<53fa11c2-6129-4171-8284-e5a796901f61@googlegroups.com>
In reply to#41226
In func() above

Note that the code also "works" (yes yes... use stdarg.h instead!) when p is changed to be an int-pointer!!!

int func(char a, char b, char c)
{
  const int *p = &a; // difference to prev: int pointer!!!!
  printf("a=%d\n"
         "b=%d\n"
         "c=%d\n", p[0],
                   p[-(int)sizeof(int)],
                   p[-(int)sizeof(int) * 2]);
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
   If you want to do something like this portable, please use stdarg.h instead!
*/
} 

[toc] | [prev] | [next] | [standalone]


#41230

Fromjononanon@googlemail.com
Date2014-03-01 01:54 -0800
Message-ID<416f2444-8530-4622-bdcb-5cdf2d4e16f2@googlegroups.com>
In reply to#41229
Ah damn, I've found some mistakes that have crept in...

I wrote:
"but all bytes comprising that int are set correctly! not just the single byte corresponding the the char."

This is not correct. Rather:
Only the space the char occupies on the stack is sizeof(int), but NOT ALL BYTES comprising that int are correctly set to correspond to the value of the char.

Proof is a FIX OF MY 2ND POST ABOVE (which was incorrect):

int func(char a, char b, char c)
{
  const int *p = &a; // difference to prev: int pointer!!!!
- hide quoted text -
  printf("a=%d\n"
         "b=%d\n"
         "c=%d\n", p[0],
                   p[-1],  // FIX
                   p[-2]); // FIX
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
   If you want to do something like this portable, please use stdarg.h instead!
*/
} 


This shows that the other bytes that are part of the stack-space (sizeof(int)), are not set correctly!

So then:
only when using variable arguments, are arguments of type char (or short) placed on the stack as correspondingly promoted int.

Ahhhh.... Sortof correct????? Maby??

[toc] | [prev] | [next] | [standalone]


#41242

FromBarry Schwarz <schwarzb@dqel.com>
Date2014-03-01 07:21 -0800
Message-ID<ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>
In reply to#41230
On Sat, 1 Mar 2014 01:54:53 -0800 (PST), jononanon@googlemail.com
wrote:

>Ah damn, I've found some mistakes that have crept in...
>
>I wrote:
>"but all bytes comprising that int are set correctly! not just the single byte corresponding the the char."
>
>This is not correct. Rather:
>Only the space the char occupies on the stack is sizeof(int), but NOT ALL BYTES comprising that int are correctly set to correspond to the value of the char.

There is no requirement for the char to occupy sizeof(int) bytes on
the stack.  This is a characteristic of your implementation that may
or may not be true on other implementations.

>
>Proof is a FIX OF MY 2ND POST ABOVE (which was incorrect):
>
>int func(char a, char b, char c)
>{
>  const int *p = &a; // difference to prev: int pointer!!!!

If a is not aligned properly for an int, then this would invoke
undefined behavior.

>- hide quoted text -
>  printf("a=%d\n"
>         "b=%d\n"
>         "c=%d\n", p[0],

Since p[0] is an int but it points to a char, any "excess" bytes not
part of a that are accessed to evaluate the int are indeterminate and
therefore this invokes undefined behavior.

>                   p[-1],  // FIX

When a pointer points to a scalar object, that object can be treated
as an array of 1.  (This is why p[0] is valid.)  However, you are not
allowed to evaluate a subscript expression where the subscript is
outside the range of the array.  (In this case, the only valid
subscript is 0.)  Doing so invokes undefined behavior.

>                   p[-2]); // FIX
>/* don't do this. might probably work on x86 with gcc (but again: don't do this)

One of the worst manifestations of undefined behavior is doing what
you expect, thus leaving you with the mistaken belief that you have
accomplished your task.

>   If you want to do something like this portable, please use stdarg.h instead!

What do you think stdarg.h has to do with using an invalid subscript?

>*/
>} 
>
>
>This shows that the other bytes that are part of the stack-space (sizeof(int)), are not set correctly!

No, it shows that invoking undefined behavior can reinforce your
preconceived assumptions.

If you wanted to examine bytes, why did you make p an int* instead of
a char*?

>So then:
>only when using variable arguments, are arguments of type char (or short) placed on the stack as correspondingly promoted int.

Variadic arguments of rank less than int are promoted to int (or
unsigned int when necessary) before being passed.  Assumptions about a
stack are extraneous.

-- 
Remove del for email

[toc] | [prev] | [next] | [standalone]


#41243

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2014-03-01 15:51 +0000
Message-ID<lesvmt$b8b$3@news.xmission.com>
In reply to#41242
In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>,
Barry Schwarz  <schwarzb@dqel.com> wrote:
...
>There is no requirement for the char to occupy sizeof(int) bytes on
>the stack.

Donning clc-pedant hat (which, admittedly, doesn't fit me very well):

    There is no requirement for there to be a stack.

And, generally, you can get yourself into trouble with the Kiki-squad if
you use "the s-word" around here.

-- 
"That's the eternal flame."[7] The single became another worldwide hit.[8]

Hoffs was actually naked when she recorded the song, after being convinced
by Sigerson that Olivia Newton-John got her amazing performances by
recording everything while naked.[9]

(From: http://en.wikipedia.org/wiki/The_Bangles)

[toc] | [prev] | [next] | [standalone]


#41245

FromRichard <rgrdev_@gmail.com>
Date2014-03-01 17:50 +0100
Message-ID<87k3cdx3qy.fsf@gmail.com>
In reply to#41243
gazelle@shell.xmission.com (Kenny McCormack) writes:

> In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>,
> Barry Schwarz  <schwarzb@dqel.com> wrote:
> ...
>>There is no requirement for the char to occupy sizeof(int) bytes on
>>the stack.
>
> Donning clc-pedant hat (which, admittedly, doesn't fit me very well):
>
>     There is no requirement for there to be a stack.
>
> And, generally, you can get yourself into trouble with the Kiki-squad if
> you use "the s-word" around here.

On the ball there. Well done. Kiki and co should be in to agree with you
any moment now...

-- 
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

[toc] | [prev] | [next] | [standalone]


#41249

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2014-03-01 18:36 +0000
Message-ID<let9bj$feu$1@news.xmission.com>
In reply to#41245
In article <87k3cdx3qy.fsf@gmail.com>, Richard  <rgrdev_@gmail.com> wrote:
>gazelle@shell.xmission.com (Kenny McCormack) writes:
>
>> In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>,
>> Barry Schwarz  <schwarzb@dqel.com> wrote:
>> ...
>>>There is no requirement for the char to occupy sizeof(int) bytes on
>>>the stack.
>>
>> Donning clc-pedant hat (which, admittedly, doesn't fit me very well):
>>
>>     There is no requirement for there to be a stack.
>>
>> And, generally, you can get yourself into trouble with the Kiki-squad if
>> you use "the s-word" around here.
>
>On the ball there. Well done. Kiki and co should be in to agree with you
>any moment now...

And that is, after all, every CLC posters primary goal - to be acknowledged
and accepted by Kiki and his coterie.

It is certainly mine...

-- 
Modern Christian: Someone who can take time out from
complaining about "welfare mothers popping out babies we
have to feed" to complain about welfare mothers getting
abortions that PREVENT more babies to be raised at public 
expense.

[toc] | [prev] | [next] | [standalone]


#41231

FromMelzzzzz <mel@zzzzz.invalid>
Date2014-03-01 11:22 +0100
Message-ID<lescdm$sl8$1@solani.org>
In reply to#41226
On Sat, 1 Mar 2014 01:29:54 -0800 (PST)
jononanon@googlemail.com wrote:

> Hi there!
> 
> Check this out -> the following code always works:
> 
> printf("%d %d %d", (char)'\1', (short)2, 3);
> // prints: 1 2 3
> 
> So a conversion specifier of %d works with type int, or "SMALLER"
> integer-types (short or char) !!!
> 
> Why does this work??

Architecture/abi is that way.

> Is my explanation correct? 
> 
> 
> 
> 
> ->
> With printf("%d", (char) '\1')
> the argument 1 lands on the stack not as char parameter, but as a
> parameter promoted to int, and the library code that handles the
> access to the parameter uses va_arg(ap, int) to access it. You can
> never use va_arg(ap, char) -> that would distroy a consistent
> handling of the stack-parameters!

On x86-64 first 6(Unix)/4(Windows) parameters are passed through 
64 bit registers. Library code does use va_arg(ap,int)
but value is correct as accessing parts of 64 bit register
is correct. Same with 32 bit , but with stack of 32 bit
bit parameters. I guess that if parameter is long
long (in case of 32bit program) your logic breaks.
I'm not sure how long long is passed but it cannot
fit in 32 bit parameter, so either it has to be split
in two parameters or pointer to it is passed.
In any case I think that would break char/int parameters.



-- 
Click OK to continue...

[toc] | [prev] | [next] | [standalone]


#41234

Fromjononanon@googlemail.com
Date2014-03-01 02:39 -0800
Message-ID<3a554fb0-085c-475f-935c-e8552586fd75@googlegroups.com>
In reply to#41231
On Saturday, March 1, 2014 11:22:45 AM UTC+1, Melzzzzz wrote:
> I'm not sure how long long is passed but it cannot
> 
> fit in 32 bit parameter, so either it has to be split
> 
> in two parameters or pointer to it is passed.
> 
> In any case I think that would break char/int parameters.
Yes, true:

printf("%lld %lld %lld\n", 1, 2, 3); /* stuffs up, if sizeof(int) < sizeof(long long) */

[toc] | [prev] | [next] | [standalone]


#41274

FromKeith Thompson <kst-u@mib.org>
Date2014-03-01 19:44 -0800
Message-ID<87vbvxuuvk.fsf@mib.org>
In reply to#41231
Melzzzzz <mel@zzzzz.invalid> writes:
> On Sat, 1 Mar 2014 01:29:54 -0800 (PST)
> jononanon@googlemail.com wrote:
>> Check this out -> the following code always works:
>> 
>> printf("%d %d %d", (char)'\1', (short)2, 3);
>> // prints: 1 2 3
>> 
>> So a conversion specifier of %d works with type int, or "SMALLER"
>> integer-types (short or char) !!!
>> 
>> Why does this work??
>
> Architecture/abi is that way.

The architecture/abi has nothing to do with it, at least not
directly.  The language standard specifies that short arguments are
converted to int in this context.  It might happen to be easier
to implement on some architectures (and architectures, ABIs, and
language standards tend to be designed to work well together),
but the compiler has to make it work regardless.

[temporarily posting through aioe.org due to problems with
eternal-september.org]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#41233

FromKeith Thompson <kst-u@mib.org>
Date2014-03-01 02:34 -0800
Message-ID<lniory438k.fsf@nuthaus.mib.org>
In reply to#41226
jononanon@googlemail.com writes:
> Hi there!
>
> Check this out -> the following code always works:
>
> printf("%d %d %d", (char)'\1', (short)2, 3);
> // prints: 1 2 3
>
> So a conversion specifier of %d works with type int, or "SMALLER"
> integer-types (short or char) !!!
>
> Why does this work??
> Is my explanation correct? 
[...]

N1570 (C11 draft) 6.5.2.2p7:

    The ellipsis notation in a function prototype declarator causes
    argument type conversion to stop after the last declared
    parameter. The default argument promotions are performed on
    trailing arguments.

The default argument promotions convert float to double, and any integer
type narrower than int is convert to int if int can represent all the
values of the type, otherwise to unsigned int.  (The latter avoids
overflow when an unsigned short value is promoted and short and int are
the same size.)

That's why, among other things, there are no specific printf formats for
float or short.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#41235

Fromjononanon@googlemail.com
Date2014-03-01 02:49 -0800
Message-ID<937c14b6-d3fa-4735-980f-fd173ccfeee3@googlegroups.com>
In reply to#41233
On Saturday, March 1, 2014 11:34:03 AM UTC+1, Keith Thompson wrote:
> any integer
> 
> type narrower than int is convert to int if int can represent all the
> 
> values of the type, otherwise to unsigned int.  (The latter avoids
> 
> overflow when an unsigned short value is promoted and short and int are
> 
> the same size.)
> 
Is this conversion to unsigned in really important?
I mean in terms of overflow! -> who cares? Isn't solely the bit-pattern important??
Because: Even if conversion were ONLY to signed int, the result via
va_arg(ap, int), or via va_arg(ap, unsigned int) is what is important. And that is not controlled by the default argument promotion, but instead by the printf-conversion-specifier. (Am I missing something?)

[toc] | [prev] | [next] | [standalone]


#41241

FromJames Kuyper <jameskuyper@verizon.net>
Date2014-03-01 09:10 -0500
Message-ID<lespp0$cjp$1@dont-email.me>
In reply to#41235
On 03/01/2014 05:49 AM, jononanon@googlemail.com wrote:
> On Saturday, March 1, 2014 11:34:03 AM UTC+1, Keith Thompson wrote:
>> any integer
>>
>> type narrower than int is convert to int if int can represent all the
>>
>> values of the type, otherwise to unsigned int.  (The latter avoids
>>
>> overflow when an unsigned short value is promoted and short and int are
>>
>> the same size.)
>>
> Is this conversion to unsigned in really important?
> I mean in terms of overflow! -> who cares? Isn't solely the bit-pattern important??

No - because there are real machines where overflow has bad consequences.

> Because: Even if conversion were ONLY to signed int, the result via
> va_arg(ap, int), or via va_arg(ap, unsigned int) is what is important. And that is not controlled by the default argument promotion, but instead by the printf-conversion-specifier. (Am I missing something?)

If the type of the argument, after promotion, differs from the type that
you specify in the corresponding invocation of va_arg(), the behavior is
undefined - such code might work, but you shouldn't count on it. When
it's just the difference between a given signed type and the
corresponding unsigned type, it's fairly safe, so long as only positive
values are involved: such are guaranteed to have the same representation
both types. No such guarantee applies to int and unsigned short, even if
they both have the same size - in principle, at least, a fully
conforming implementation could, for example, have big-endian int, and
little-endian unsigned short.

In this particular case, you can probably get away with sloppy coding
that ignores these issues - but it's better to handle it correctly. If
there's a possibility that a given value that is subject to the default
promotions might promote to either int or unsigned int, depending upon
the characteristics of the implementation you're using, you should write
your code to either remove that possibility, or deal with it.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#41266

From<william@wilbur.25thandClement.com>
Date2014-03-01 15:38 -0800
Message-ID<el7aua-9bg.ln1@wilbur.25thandClement.com>
In reply to#41233
Keith Thompson <kst-u@mib.org> wrote:
> jononanon@googlemail.com writes:
>> Hi there!
>>
>> Check this out -> the following code always works:
>>
>> printf("%d %d %d", (char)'\1', (short)2, 3);
>> // prints: 1 2 3
>>
>> So a conversion specifier of %d works with type int, or "SMALLER"
>> integer-types (short or char) !!!
>>
>> Why does this work??
>> Is my explanation correct? 
> [...]
> 
> N1570 (C11 draft) 6.5.2.2p7:
> 
>    The ellipsis notation in a function prototype declarator causes
>    argument type conversion to stop after the last declared
>    parameter. The default argument promotions are performed on
>    trailing arguments.
> 
> The default argument promotions convert float to double, and any integer
> type narrower than int is convert to int if int can represent all the
> values of the type, otherwise to unsigned int.  (The latter avoids
> overflow when an unsigned short value is promoted and short and int are
> the same size.)
> 
> That's why, among other things, there are no specific printf formats for
> float or short.

There's the `h' length modifier for shorts. Also `hh' for chars.

[toc] | [prev] | [next] | [standalone]


#41275

FromKeith Thompson <kst-u@mib.org>
Date2014-03-01 19:47 -0800
Message-ID<87r46luuqw.fsf@mib.org>
In reply to#41266
<william@wilbur.25thandClement.com> writes:
> Keith Thompson <kst-u@mib.org> wrote:
[...]
>> The default argument promotions convert float to double, and any
>> integer type narrower than int is convert to int if int can represent
>> all the values of the type, otherwise to unsigned int.  (The latter
>> avoids overflow when an unsigned short value is promoted and short
>> and int are the same size.)
>> 
>> That's why, among other things, there are no specific printf formats
>> for float or short.
>
> There's the `h' length modifier for shorts. Also `hh' for chars.

Good point, I momentarily forgot about those.

"%hd" still requires an int argument (possibly promoted from short),
but the value is *converted* to short before printing.  I'm actually
not sure what it's good for.  If the argument is already in the
range of type short, then it behaves identically to "%d"; if it's
outside that range, the result is implementation-defined (or, at
least in principle, it can raise an implementation-defined signal).

At least for "%hu" or "%hx", the behavior of the conversion is well
defined, but the behavior is still identical to "%u" or "%x" if the
argument is of type unsigned short.  But I'm really not sure why the "h"
and "hh" length modifiers were added to the language.  ("h" was added in
ANSI C89, "hh" in C99.)

[temporarily posting through aioe.org due to problems with
eternal-september.org]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#41277

From<william@wilbur.25thandClement.com>
Date2014-03-01 21:12 -0800
Message-ID<97raua-i3l.ln1@wilbur.25thandClement.com>
In reply to#41275
Keith Thompson <kst-u@mib.org> wrote:
> <william@wilbur.25thandClement.com> writes:
>> Keith Thompson <kst-u@mib.org> wrote:
> [...]
>>> The default argument promotions convert float to double, and any
>>> integer type narrower than int is convert to int if int can represent
>>> all the values of the type, otherwise to unsigned int.  (The latter
>>> avoids overflow when an unsigned short value is promoted and short
>>> and int are the same size.)
>>> 
>>> That's why, among other things, there are no specific printf formats
>>> for float or short.
>>
>> There's the `h' length modifier for shorts. Also `hh' for chars.
> 
> Good point, I momentarily forgot about those.
> 
> "%hd" still requires an int argument (possibly promoted from short),
> but the value is *converted* to short before printing.  I'm actually
> not sure what it's good for.  If the argument is already in the
> range of type short, then it behaves identically to "%d"; if it's
> outside that range, the result is implementation-defined (or, at
> least in principle, it can raise an implementation-defined signal).

I submitted a bug report to Apple for an issue related to %hu, which they
dutifully fixed in a subsequent release.

Their version of the ntohs() routine, because of their use of a ternary
operator, resulted in an expression of int type, rather than the documented
uint16_t. The original code looked like

((__builtin_constant_p(x) ? __DARWIN_OSSwapConstInt16(x) : _OSSwapInt16(x)))

The fix was to cast the result. See /usr/include/libkern/_OSByteOrder.h.

GCC's printf checker never caught this issue. The type was ultimately
promoted to int, anyhow, so using %hu with an int parameter was
inconsequential.

clang, however, wasn't as forgiving. I began using upstream clang before
Apple swapped in clang for their GCC frontend, and apparently was one of the
first people to spot this issue. (Or maybe just the first one to care.)

One could quibble whether GCC should have complained or whether clang should
have remained silent. But I choose to file the bug with Apple and not clang.


Note: On recent OS X verions /usr/bin/gcc is a tweaked version of clang, so
merely invoking `gcc' will still result in warnings. gcc 4.8's printf
checker still accepts int expressions for %hd without a diagnostic.

[toc] | [prev] | [next] | [standalone]


#41292

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2014-03-02 07:47 -0700
Message-ID<1bk3cc4pzt.fsf@snowball.wb.pfeifferfamily.net>
In reply to#41275
Keith Thompson <kst-u@mib.org> writes:

> <william@wilbur.25thandClement.com> writes:
>> Keith Thompson <kst-u@mib.org> wrote:
> [...]
>>> The default argument promotions convert float to double, and any
>>> integer type narrower than int is convert to int if int can represent
>>> all the values of the type, otherwise to unsigned int.  (The latter
>>> avoids overflow when an unsigned short value is promoted and short
>>> and int are the same size.)
>>> 
>>> That's why, among other things, there are no specific printf formats
>>> for float or short.
>>
>> There's the `h' length modifier for shorts. Also `hh' for chars.
>
> Good point, I momentarily forgot about those.
>
> "%hd" still requires an int argument (possibly promoted from short),
> but the value is *converted* to short before printing.  I'm actually
> not sure what it's good for.  If the argument is already in the
> range of type short, then it behaves identically to "%d"; if it's
> outside that range, the result is implementation-defined (or, at
> least in principle, it can raise an implementation-defined signal).

I always assumed that it was for consistency with scanf.

> At least for "%hu" or "%hx", the behavior of the conversion is well
> defined, but the behavior is still identical to "%u" or "%x" if the
> argument is of type unsigned short.  But I'm really not sure why the "h"
> and "hh" length modifiers were added to the language.  ("h" was added in
> ANSI C89, "hh" in C99.)
>
> [temporarily posting through aioe.org due to problems with
> eternal-september.org]

[toc] | [prev] | [next] | [standalone]


#41309

FromKaz Kylheku <kaz@kylheku.com>
Date2014-03-02 20:53 +0000
Message-ID<20140302125139.273@kylheku.com>
In reply to#41292
On 2014-03-02, Joe Pfeiffer <pfeiffer@cs.nmsu.edu> wrote:
> Keith Thompson <kst-u@mib.org> writes:
>
>> <william@wilbur.25thandClement.com> writes:
>>> Keith Thompson <kst-u@mib.org> wrote:
>> [...]
>>>> The default argument promotions convert float to double, and any
>>>> integer type narrower than int is convert to int if int can represent
>>>> all the values of the type, otherwise to unsigned int.  (The latter
>>>> avoids overflow when an unsigned short value is promoted and short
>>>> and int are the same size.)
>>>> 
>>>> That's why, among other things, there are no specific printf formats
>>>> for float or short.
>>>
>>> There's the `h' length modifier for shorts. Also `hh' for chars.
>>
>> Good point, I momentarily forgot about those.
>>
>> "%hd" still requires an int argument (possibly promoted from short),
>> but the value is *converted* to short before printing.  I'm actually
>> not sure what it's good for.  If the argument is already in the
>> range of type short, then it behaves identically to "%d"; if it's
>> outside that range, the result is implementation-defined (or, at
>> least in principle, it can raise an implementation-defined signal).
>
> I always assumed that it was for consistency with scanf.

There are blatant inconsistencies like:

 printf("%f", double_var);

 scanf("%f", &double_var);  /* error */

 scanf("%lf", &double_var);  /* correct */

The consistency ship sailed long ago; printf and scanf missed it.

[toc] | [prev] | [next] | [standalone]


#41338

Fromjgk@panix.com (Joe keane)
Date2014-03-04 00:23 +0000
Message-ID<lf36ej$rg5$1@reader1.panix.com>
In reply to#41309
In article <20140302125139.273@kylheku.com>,
Kaz Kylheku  <kaz@kylheku.com> wrote:
>There are blatant inconsistencies like:
>
> printf("%f", double_var);
>
> scanf("%f", &double_var);  /* error */
>
> scanf("%lf", &double_var);  /* correct */

First one should be "lf" ('long float').

When calling a varargs function it is legal to pass 'float' where
'double' is expected and vice versa.

A lot of rules for 'float' were changed, just not this one.

So there is your problem.

The 'printf' side has always been more tolerant; screwing up a 'scanf'
format will quickly crash, if you're lucky...

[toc] | [prev] | [next] | [standalone]


#41339

FromKaz Kylheku <kaz@kylheku.com>
Date2014-03-04 00:33 +0000
Message-ID<20140303162419.577@kylheku.com>
In reply to#41338
On 2014-03-04, Joe keane <jgk@panix.com> wrote:
> In article <20140302125139.273@kylheku.com>,
> Kaz Kylheku  <kaz@kylheku.com> wrote:
>>There are blatant inconsistencies like:
>>
>> printf("%f", double_var);
>>
>> scanf("%f", &double_var);  /* error */
>>
>> scanf("%lf", &double_var);  /* correct */
>
> First one should be "lf" ('long float').

Nope. %f takes double.

  "f,F A double argument representing a floating-point number is converted to
  decimal notation in the style [−]ddd.ddd, where the number of digits after
  the decimal-point character is equal to the precision specification."
  (ISO/IEC 9899:1999)

Where is %g and %e in scanf? If printf were consistent with scanf,
%g would scan the general printed representation that may use exponents
or not, %f would scan only [-]ddd.ddd, and %e only exponentials.

%f in printf perhaps doesn't stand for "floating". It means "fixed digits": 
in a sense the opposite of a "floating" decimal point with an exponent.

> When calling a varargs function it is legal to pass 'float' where
> 'double' is expected and vice versa.

When calling a varargs function, it is impossible to pass a float;
any such expression widens to a double.

> A lot of rules for 'float' were changed, just not this one.

Recently? In what way?

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web